Add tool annotations and PR close/reopen support (#174)

Add MCP `ToolAnnotation` metadata (Title, ReadOnlyHint, DestructiveHint)
to all registered tools so MCP hosts (VS Code, Claude, Cursor) get
accurate per-tool hints. A shared `pkg/annotation` package exposes
`ReadOnly`, `Write`, and `Destructive` helpers for consistency.

Add `close` and `reopen` methods to `pull_request_write` so PR state
can be toggled without going through the generic `update` path.

Co-Authored-By: silverwind <me@silverwind.io>
Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
This commit is contained in:
unpossible
2026-05-10 11:25:22 +02:00
committed by silverwind
parent 4c45b42cb5
commit 329a97d5d2
21 changed files with 296 additions and 2 deletions
+3
View File
@@ -8,6 +8,7 @@ import (
"strconv"
"time"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -48,6 +49,7 @@ var (
ActionsConfigReadTool = mcp.NewTool(
ActionsConfigReadToolName,
mcp.WithDescription("Read Actions secrets and variables configuration."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read Actions secrets and variables")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list_repo_secrets", "list_org_secrets", "list_repo_variables", "get_repo_variable", "list_org_variables", "get_org_variable")),
mcp.WithString("owner", mcp.Description("repository owner (required for repo methods)")),
mcp.WithString("repo", mcp.Description("repository name (required for repo methods)")),
@@ -60,6 +62,7 @@ var (
ActionsConfigWriteTool = mcp.NewTool(
ActionsConfigWriteToolName,
mcp.WithDescription("Manage Actions secrets and variables: create, update, or delete."),
mcp.WithToolAnnotation(annotation.Destructive("Manage Actions secrets and variables")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("upsert_repo_secret", "delete_repo_secret", "upsert_org_secret", "delete_org_secret", "create_repo_variable", "update_repo_variable", "delete_repo_variable", "create_org_variable", "update_org_variable", "delete_org_variable")),
mcp.WithString("owner", mcp.Description("repository owner (required for repo methods)")),
mcp.WithString("repo", mcp.Description("repository name (required for repo methods)")),
+3
View File
@@ -10,6 +10,7 @@ import (
"path/filepath"
"strconv"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -28,6 +29,7 @@ var (
ActionsRunReadTool = mcp.NewTool(
ActionsRunReadToolName,
mcp.WithDescription("Read Actions workflow, run, and job data. Use method 'list_workflows'/'get_workflow' for workflows, 'list_runs'/'get_run' for runs, 'list_jobs'/'list_run_jobs' for jobs, 'get_job_log_preview'/'download_job_log' for logs."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read Actions workflow, run, and job data")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list_workflows", "get_workflow", "list_runs", "get_run", "list_jobs", "list_run_jobs", "get_job_log_preview", "download_job_log")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
@@ -45,6 +47,7 @@ var (
ActionsRunWriteTool = mcp.NewTool(
ActionsRunWriteToolName,
mcp.WithDescription("Trigger, cancel, or rerun Actions workflows."),
mcp.WithToolAnnotation(annotation.Write("Trigger, cancel, or rerun Actions workflows")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("dispatch_workflow", "cancel_run", "rerun_run")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
+4
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"net/url"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -40,6 +41,7 @@ var (
ListRepoIssuesTool = mcp.NewTool(
ListRepoIssuesToolName,
mcp.WithDescription("List repository issues"),
mcp.WithToolAnnotation(annotation.ReadOnly("List repository issues")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("state", mcp.Description("issue state"), mcp.DefaultString("all")),
@@ -53,6 +55,7 @@ var (
IssueReadTool = mcp.NewTool(
IssueReadToolName,
mcp.WithDescription("Get information about a specific issue. Use method 'get' for issue details, 'get_comments' for issue comments, 'get_labels' for issue labels."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read issue details")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("get", "get_comments", "get_labels")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
@@ -62,6 +65,7 @@ var (
IssueWriteTool = mcp.NewTool(
IssueWriteToolName,
mcp.WithDescription("Create or update issues and comments, manage labels. Use method 'create' to create an issue, 'update' to edit, 'add_comment'/'edit_comment' for comments, 'add_labels'/'remove_label'/'replace_labels'/'clear_labels' for label management."),
mcp.WithToolAnnotation(annotation.Write("Create or update issues, comments, and labels")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("create", "update", "add_comment", "edit_comment", "add_labels", "remove_label", "replace_labels", "clear_labels")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
+3
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -26,6 +27,7 @@ var (
LabelReadTool = mcp.NewTool(
LabelReadToolName,
mcp.WithDescription("Read label information. Use method 'list_repo_labels' to list repository labels, 'get_repo_label' to get a specific repo label, 'list_org_labels' to list organization labels."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read labels")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list_repo_labels", "get_repo_label", "list_org_labels")),
mcp.WithString("owner", mcp.Description("repository owner (required for repo methods)")),
mcp.WithString("repo", mcp.Description("repository name (required for repo methods)")),
@@ -38,6 +40,7 @@ var (
LabelWriteTool = mcp.NewTool(
LabelWriteToolName,
mcp.WithDescription("Create, edit, or delete labels for repositories or organizations."),
mcp.WithToolAnnotation(annotation.Destructive("Create, update, or delete labels")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("create_repo_label", "edit_repo_label", "delete_repo_label", "create_org_label", "edit_org_label", "delete_org_label")),
mcp.WithString("owner", mcp.Description("repository owner (required for repo methods)")),
mcp.WithString("repo", mcp.Description("repository name (required for repo methods)")),
+3
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -26,6 +27,7 @@ var (
MilestoneReadTool = mcp.NewTool(
MilestoneReadToolName,
mcp.WithDescription("Read milestone information. Use method 'get' to get a specific milestone, 'list' to list milestones."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read milestones")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("get", "list")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
@@ -39,6 +41,7 @@ var (
MilestoneWriteTool = mcp.NewTool(
MilestoneWriteToolName,
mcp.WithDescription("Create, edit, or delete milestones."),
mcp.WithToolAnnotation(annotation.Destructive("Create, update, or delete milestones")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("create", "edit", "delete")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
+3
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"time"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -27,6 +28,7 @@ var (
NotificationReadTool = mcp.NewTool(
NotificationReadToolName,
mcp.WithDescription("Get notifications. Use method 'list' to list notifications (optionally scoped to a repo), 'get' to get a single notification thread by ID."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read notifications")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list", "get")),
mcp.WithString("owner", mcp.Description("repository owner (for 'list' to scope to a repo)")),
mcp.WithString("repo", mcp.Description("repository name (for 'list' to scope to a repo)")),
@@ -42,6 +44,7 @@ var (
NotificationWriteTool = mcp.NewTool(
NotificationWriteToolName,
mcp.WithDescription("Manage notifications. Use method 'mark_read' to mark a single notification as read, 'mark_all_read' to mark all notifications as read (optionally scoped to a repo)."),
mcp.WithToolAnnotation(annotation.Write("Manage notifications")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("mark_read", "mark_all_read")),
mcp.WithNumber("id", mcp.Description("notification thread ID (required for 'mark_read')")),
mcp.WithString("owner", mcp.Description("repository owner (for 'mark_all_read' to scope to a repo)")),
+71 -2
View File
@@ -6,6 +6,7 @@ import (
"net/url"
"strings"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -30,6 +31,7 @@ var (
ListRepoPullRequestsTool = mcp.NewTool(
ListRepoPullRequestsToolName,
mcp.WithDescription("List repository pull requests"),
mcp.WithToolAnnotation(annotation.ReadOnly("List pull requests")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("state", mcp.Description("state"), mcp.Enum("open", "closed", "all"), mcp.DefaultString("all")),
@@ -42,6 +44,7 @@ var (
PullRequestReadTool = mcp.NewTool(
PullRequestReadToolName,
mcp.WithDescription("Get pull request information. Use method 'get' for PR details, 'get_diff' for diff, 'get_reviews'/'get_review'/'get_review_comments' for review data."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read pull request details")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("get", "get_diff", "get_reviews", "get_review", "get_review_comments")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
@@ -54,8 +57,9 @@ var (
PullRequestWriteTool = mcp.NewTool(
PullRequestWriteToolName,
mcp.WithDescription("Create, update, or merge pull requests, manage reviewers."),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("create", "update", "merge", "add_reviewers", "remove_reviewers")),
mcp.WithDescription("Create, update, close, reopen, or merge pull requests, manage reviewers."),
mcp.WithToolAnnotation(annotation.Write("Create, update, close, reopen, or merge pull requests")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("create", "update", "close", "reopen", "merge", "add_reviewers", "remove_reviewers")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithNumber("index", mcp.Description("pull request index (required for all methods except 'create')")),
@@ -85,6 +89,7 @@ var (
PullRequestReviewWriteTool = mcp.NewTool(
PullRequestReviewWriteToolName,
mcp.WithDescription("Manage pull request reviews: create, submit, delete, or dismiss."),
mcp.WithToolAnnotation(annotation.Write("Submit a pull request review")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("create", "submit", "delete", "dismiss")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
@@ -156,6 +161,10 @@ func pullRequestWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
return createPullRequestFn(ctx, req)
case "update":
return editPullRequestFn(ctx, req)
case "close":
return closePullRequestFn(ctx, req)
case "reopen":
return reopenPullRequestFn(ctx, req)
case "merge":
return mergePullRequestFn(ctx, req)
case "add_reviewers":
@@ -167,6 +176,66 @@ func pullRequestWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Call
}
}
func closePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
owner, err := params.GetString(req.GetArguments(), "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(req.GetArguments(), "repo")
if err != nil {
return to.ErrorResult(err)
}
index, err := params.GetIndex(req.GetArguments(), "index")
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))
}
state := gitea_sdk.StateClosed
pr, _, err := client.EditPullRequest(owner, repo, index, gitea_sdk.EditPullRequestOption{
State: &state,
})
if err != nil {
return to.ErrorResult(fmt.Errorf("close %v/%v/pr/%v err: %v", owner, repo, index, err))
}
return to.TextResult(slimPullRequest(pr))
}
func reopenPullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
owner, err := params.GetString(req.GetArguments(), "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(req.GetArguments(), "repo")
if err != nil {
return to.ErrorResult(err)
}
index, err := params.GetIndex(req.GetArguments(), "index")
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))
}
state := gitea_sdk.StateOpen
pr, _, err := client.EditPullRequest(owner, repo, index, gitea_sdk.EditPullRequestOption{
State: &state,
})
if err != nil {
return to.ErrorResult(fmt.Errorf("reopen %v/%v/pr/%v err: %v", owner, repo, index, err))
}
return to.TextResult(slimPullRequest(pr))
}
func pullRequestReviewWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
method, err := params.GetString(req.GetArguments(), "method")
if err != nil {
+128
View File
@@ -911,3 +911,131 @@ func Test_getPullRequestByIndexFn_assetsFailureNonFatal(t *testing.T) {
t.Fatalf("expected PR body preserved when assets fail, got: %s", body)
}
}
func Test_closePullRequestFn(t *testing.T) {
const (
owner = "octo"
repo = "demo"
index = 7
)
var 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.12.0"}`))
case fmt.Sprintf("/api/v1/repos/%s/%s", owner, repo):
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"private":false}`))
case fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner, repo, index):
if r.Method != http.MethodPatch {
t.Errorf("expected PATCH method, got %s", r.Method)
}
_ = json.NewDecoder(r.Body).Decode(&gotBody)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(fmt.Appendf(nil, `{"index":%d,"title":"Fix bug","state":"closed","head":{"ref":"fix-branch"},"base":{"ref":"main"}}`, index))
default:
t.Errorf("unexpected request: %s %s", r.Method, r.URL.Path)
w.WriteHeader(http.StatusNotFound)
}
})
server := httptest.NewServer(handler)
t.Cleanup(server.Close)
origHost := flag.Host
origToken := flag.Token
flag.Host = server.URL
flag.Token = "test-token"
t.Cleanup(func() { flag.Host = origHost; flag.Token = origToken })
req := mcp.CallToolRequest{
Params: mcp.CallToolParams{
Arguments: map[string]any{
"method": "close",
"owner": owner,
"repo": repo,
"index": float64(index),
},
},
}
result, err := closePullRequestFn(context.Background(), req)
if err != nil {
t.Fatalf("closePullRequestFn() error = %v", err)
}
if gotBody["state"] != "closed" {
t.Errorf("expected state=closed, got %v", gotBody["state"])
}
if len(result.Content) == 0 {
t.Fatalf("expected content in result")
}
}
func Test_reopenPullRequestFn(t *testing.T) {
const (
owner = "octo"
repo = "demo"
index = 7
)
var 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.12.0"}`))
case fmt.Sprintf("/api/v1/repos/%s/%s", owner, repo):
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"private":false}`))
case fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d", owner, repo, index):
if r.Method != http.MethodPatch {
t.Errorf("expected PATCH method, got %s", r.Method)
}
_ = json.NewDecoder(r.Body).Decode(&gotBody)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(fmt.Appendf(nil, `{"index":%d,"title":"Fix bug","state":"open","head":{"ref":"fix-branch"},"base":{"ref":"main"}}`, index))
default:
t.Errorf("unexpected request: %s %s", r.Method, r.URL.Path)
w.WriteHeader(http.StatusNotFound)
}
})
server := httptest.NewServer(handler)
t.Cleanup(server.Close)
origHost := flag.Host
origToken := flag.Token
flag.Host = server.URL
flag.Token = "test-token"
t.Cleanup(func() { flag.Host = origHost; flag.Token = origToken })
req := mcp.CallToolRequest{
Params: mcp.CallToolParams{
Arguments: map[string]any{
"method": "reopen",
"owner": owner,
"repo": repo,
"index": float64(index),
},
},
}
result, err := reopenPullRequestFn(context.Background(), req)
if err != nil {
t.Fatalf("reopenPullRequestFn() error = %v", err)
}
if gotBody["state"] != "open" {
t.Errorf("expected state=open, got %v", gotBody["state"])
}
if len(result.Content) == 0 {
t.Fatalf("expected content in result")
}
}
+4
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -24,6 +25,7 @@ var (
CreateBranchTool = mcp.NewTool(
CreateBranchToolName,
mcp.WithDescription("Create branch"),
mcp.WithToolAnnotation(annotation.Write("Create a new branch")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("branch", mcp.Required(), mcp.Description("Name of the branch to create")),
@@ -33,6 +35,7 @@ var (
DeleteBranchTool = mcp.NewTool(
DeleteBranchToolName,
mcp.WithDescription("Delete branch"),
mcp.WithToolAnnotation(annotation.Destructive("Delete a branch")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("branch", mcp.Required(), mcp.Description("Name of the branch to delete")),
@@ -41,6 +44,7 @@ var (
ListBranchesTool = mcp.NewTool(
ListBranchesToolName,
mcp.WithDescription("List branches"),
mcp.WithToolAnnotation(annotation.ReadOnly("List repository branches")),
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)),
+3
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -23,6 +24,7 @@ var (
ListRepoCommitsTool = mcp.NewTool(
ListRepoCommitsToolName,
mcp.WithDescription("List repository commits"),
mcp.WithToolAnnotation(annotation.ReadOnly("List repository commits")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("sha", mcp.Description("SHA or branch to start listing commits from")),
@@ -34,6 +36,7 @@ var (
GetCommitTool = mcp.NewTool(
GetCommitToolName,
mcp.WithDescription("Get details of a specific commit"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get commit details")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("sha", mcp.Required(), mcp.Description("commit SHA")),
+5
View File
@@ -8,6 +8,7 @@ import (
"encoding/json"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -29,6 +30,7 @@ var (
GetFileContentTool = mcp.NewTool(
GetFileToolName,
mcp.WithDescription("Get file Content and Metadata"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get file content")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("ref", mcp.Required(), mcp.Description("ref can be branch/tag/commit")),
@@ -39,6 +41,7 @@ var (
GetDirContentTool = mcp.NewTool(
GetDirToolName,
mcp.WithDescription("Get a list of entries in a directory"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get directory contents")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("ref", mcp.Required(), mcp.Description("ref can be branch/tag/commit")),
@@ -48,6 +51,7 @@ var (
CreateOrUpdateFileTool = mcp.NewTool(
CreateOrUpdateFileToolName,
mcp.WithDescription("Create or update a file. If sha is provided, updates the existing file; otherwise creates a new file."),
mcp.WithToolAnnotation(annotation.Write("Create or update a file")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("filePath", mcp.Required(), mcp.Description("file path")),
@@ -61,6 +65,7 @@ var (
DeleteFileTool = mcp.NewTool(
DeleteFileToolName,
mcp.WithDescription("Delete file"),
mcp.WithToolAnnotation(annotation.Destructive("Delete a file")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("filePath", mcp.Required(), mcp.Description("file path")),
+6
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -26,6 +27,7 @@ var (
CreateReleaseTool = mcp.NewTool(
CreateReleaseToolName,
mcp.WithDescription("Create release"),
mcp.WithToolAnnotation(annotation.Write("Create a release")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
@@ -39,6 +41,7 @@ var (
DeleteReleaseTool = mcp.NewTool(
DeleteReleaseToolName,
mcp.WithDescription("Delete release"),
mcp.WithToolAnnotation(annotation.Destructive("Delete a release")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithNumber("id", mcp.Required(), mcp.Description("release id")),
@@ -47,6 +50,7 @@ var (
GetReleaseTool = mcp.NewTool(
GetReleaseToolName,
mcp.WithDescription("Get release"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get release details")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithNumber("id", mcp.Required(), mcp.Description("release id")),
@@ -55,6 +59,7 @@ var (
GetLatestReleaseTool = mcp.NewTool(
GetLatestReleaseToolName,
mcp.WithDescription("Get latest release"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get latest release")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
)
@@ -62,6 +67,7 @@ var (
ListReleasesTool = mcp.NewTool(
ListReleasesToolName,
mcp.WithDescription("List releases"),
mcp.WithToolAnnotation(annotation.ReadOnly("List releases")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithBoolean("is_draft", mcp.Description("Whether the release is draft"), mcp.DefaultBool(false)),
+5
View File
@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -29,6 +30,7 @@ var (
CreateRepoTool = mcp.NewTool(
CreateRepoToolName,
mcp.WithDescription("Create repository in personal account or organization"),
mcp.WithToolAnnotation(annotation.Write("Create a new repository")),
mcp.WithString("name", mcp.Required(), mcp.Description("Name of the repository to create")),
mcp.WithString("description", mcp.Description("Description of the repository to create")),
mcp.WithBoolean("private", mcp.Description("Whether the repository is private")),
@@ -47,6 +49,7 @@ var (
ForkRepoTool = mcp.NewTool(
ForkRepoToolName,
mcp.WithDescription("Fork repository"),
mcp.WithToolAnnotation(annotation.Write("Fork a repository")),
mcp.WithString("user", mcp.Required(), mcp.Description("User name of the repository to fork")),
mcp.WithString("repo", mcp.Required(), mcp.Description("Repository name to fork")),
mcp.WithString("organization", mcp.Description("Organization name to fork")),
@@ -56,6 +59,7 @@ var (
ListMyReposTool = mcp.NewTool(
ListMyReposToolName,
mcp.WithDescription("List my repositories"),
mcp.WithToolAnnotation(annotation.ReadOnly("List my repositories")),
mcp.WithNumber("page", mcp.Required(), mcp.Description("Page number"), mcp.DefaultNumber(1), mcp.Min(1)),
mcp.WithNumber("perPage", mcp.Required(), mcp.Description("results per page (may be capped by the server's MAX_RESPONSE_ITEMS setting, default 50)"), mcp.DefaultNumber(30), mcp.Min(1)),
)
@@ -63,6 +67,7 @@ var (
ListOrgReposTool = mcp.NewTool(
ListOrgReposToolName,
mcp.WithDescription("List repositories of an organization"),
mcp.WithToolAnnotation(annotation.ReadOnly("List organization repositories")),
mcp.WithString("org", mcp.Required(), mcp.Description("Organization name")),
mcp.WithNumber("page", mcp.Required(), mcp.Description("Page number"), mcp.DefaultNumber(1), mcp.Min(1)),
mcp.WithNumber("pageSize", mcp.Required(), mcp.Description("Page size number"), mcp.DefaultNumber(100), mcp.Min(1)),
+5
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -25,6 +26,7 @@ var (
CreateTagTool = mcp.NewTool(
CreateTagToolName,
mcp.WithDescription("Create tag"),
mcp.WithToolAnnotation(annotation.Write("Create a tag")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
@@ -35,6 +37,7 @@ var (
DeleteTagTool = mcp.NewTool(
DeleteTagToolName,
mcp.WithDescription("Delete tag"),
mcp.WithToolAnnotation(annotation.Destructive("Delete a tag")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
@@ -43,6 +46,7 @@ var (
GetTagTool = mcp.NewTool(
GetTagToolName,
mcp.WithDescription("Get tag"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get tag details")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("tag_name", mcp.Required(), mcp.Description("tag name")),
@@ -51,6 +55,7 @@ var (
ListTagsTool = mcp.NewTool(
ListTagsToolName,
mcp.WithDescription("List tags"),
mcp.WithToolAnnotation(annotation.ReadOnly("List tags")),
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.Min(1)),
+2
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -21,6 +22,7 @@ const (
var GetRepoTreeTool = mcp.NewTool(
GetRepoTreeToolName,
mcp.WithDescription("Get the file tree of a repository"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get repository file tree")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("tree_sha", mcp.Required(), mcp.Description("SHA, branch name, or tag name")),
+5
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"strings"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -29,6 +30,7 @@ var (
SearchUsersTool = mcp.NewTool(
SearchUsersToolName,
mcp.WithDescription("search users"),
mcp.WithToolAnnotation(annotation.ReadOnly("Search users")),
mcp.WithString("keyword", mcp.Required(), mcp.Description("Keyword")),
mcp.WithNumber("page", mcp.Description("Page"), mcp.DefaultNumber(1)),
mcp.WithNumber("perPage", mcp.Description("results per page (may be capped by the server's MAX_RESPONSE_ITEMS setting, default 50)"), mcp.DefaultNumber(30)),
@@ -37,6 +39,7 @@ var (
SearOrgTeamsTool = mcp.NewTool(
SearchOrgTeamsToolName,
mcp.WithDescription("search organization teams"),
mcp.WithToolAnnotation(annotation.ReadOnly("Search organization teams")),
mcp.WithString("org", mcp.Required(), mcp.Description("organization name")),
mcp.WithString("query", mcp.Required(), mcp.Description("search organization teams")),
mcp.WithBoolean("includeDescription", mcp.Description("include description?")),
@@ -47,6 +50,7 @@ var (
SearchReposTool = mcp.NewTool(
SearchReposToolName,
mcp.WithDescription("search repos"),
mcp.WithToolAnnotation(annotation.ReadOnly("Search repositories")),
mcp.WithString("keyword", mcp.Required(), mcp.Description("Keyword")),
mcp.WithBoolean("keywordIsTopic", mcp.Description("KeywordIsTopic")),
mcp.WithBoolean("keywordInDescription", mcp.Description("KeywordInDescription")),
@@ -62,6 +66,7 @@ var (
SearchIssuesTool = mcp.NewTool(
SearchIssuesToolName,
mcp.WithDescription("Search for issues and pull requests across all accessible repositories"),
mcp.WithToolAnnotation(annotation.ReadOnly("Search issues")),
mcp.WithString("query", mcp.Required(), mcp.Description("search keyword")),
mcp.WithString("state", mcp.Description("filter by state: open, closed, all"), mcp.Enum("open", "closed", "all")),
mcp.WithString("type", mcp.Description("filter by type: issues, pulls"), mcp.Enum("issues", "pulls")),
+3
View File
@@ -5,6 +5,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -27,6 +28,7 @@ var (
TimetrackingReadTool = mcp.NewTool(
TimetrackingReadToolName,
mcp.WithDescription("Read time tracking data. Use method 'list_issue_times' for issue times, 'list_repo_times' for repository times, 'get_my_stopwatches' for active stopwatches, 'get_my_times' for all your tracked times."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read tracked time")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list_issue_times", "list_repo_times", "get_my_stopwatches", "get_my_times")),
mcp.WithString("owner", mcp.Description("repository owner (required for 'list_issue_times', 'list_repo_times')")),
mcp.WithString("repo", mcp.Description("repository name (required for 'list_issue_times', 'list_repo_times')")),
@@ -38,6 +40,7 @@ var (
TimetrackingWriteTool = mcp.NewTool(
TimetrackingWriteToolName,
mcp.WithDescription("Manage time tracking: stopwatches and tracked time entries."),
mcp.WithToolAnnotation(annotation.Write("Add or manage tracked time")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("start_stopwatch", "stop_stopwatch", "delete_stopwatch", "add_time", "delete_time")),
mcp.WithString("owner", mcp.Description("repository owner (required for all methods)")),
mcp.WithString("repo", mcp.Description("repository name (required for all methods)")),
+3
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -36,6 +37,7 @@ var (
GetMyUserInfoTool = mcp.NewTool(
GetMyUserInfoToolName,
mcp.WithDescription("Get my user info"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get current user information")),
)
// GetUserOrgsTool is the MCP tool for listing organizations for the authenticated user.
@@ -43,6 +45,7 @@ var (
GetUserOrgsTool = mcp.NewTool(
GetUserOrgsToolName,
mcp.WithDescription("Get organizations associated with the authenticated user"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get user organizations")),
mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(defaultPage)),
mcp.WithNumber("perPage", mcp.Description("results per page (may be capped by the server's MAX_RESPONSE_ITEMS setting, default 50)"), mcp.DefaultNumber(defaultPageSize)),
)
+2
View File
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/flag"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/to"
@@ -22,6 +23,7 @@ const (
var GetGiteaMCPServerVersionTool = mcp.NewTool(
GetGiteaMCPServerVersion,
mcp.WithDescription("Get Gitea MCP Server Version"),
mcp.WithToolAnnotation(annotation.ReadOnly("Get server version")),
)
func init() {
+3
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"net/url"
"gitea.com/gitea/gitea-mcp/pkg/annotation"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
"gitea.com/gitea/gitea-mcp/pkg/log"
"gitea.com/gitea/gitea-mcp/pkg/params"
@@ -27,6 +28,7 @@ var (
WikiReadTool = mcp.NewTool(
WikiReadToolName,
mcp.WithDescription("Read wiki page information. Use method 'list' to list pages, 'get' to get page content, 'get_revisions' for revision history."),
mcp.WithToolAnnotation(annotation.ReadOnly("Read wiki pages")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list", "get", "get_revisions")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
@@ -36,6 +38,7 @@ var (
WikiWriteTool = mcp.NewTool(
WikiWriteToolName,
mcp.WithDescription("Create, update, or delete wiki pages."),
mcp.WithToolAnnotation(annotation.Destructive("Create, update, or delete wiki pages")),
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("create", "update", "delete")),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),