Add release and tags related funcions #25
@@ -154,6 +154,15 @@ The Gitea MCP Server supports the following tools: | ||||
| create_branch | Branch | Create a new branch | | ||||
| delete_branch | Branch | Delete a branch | | ||||
| list_branches | Branch | List all branches in a repository | | ||||
| create_release | Release | Create a new release in a repository | | ||||
| delete_release | Release | Delete a release from a repository | | ||||
| get_release | Release | Get a release | | ||||
| get_latest_release | Release | Get the latest release in a repository | | ||||
| list_releases | Release | List all releases in a repository | | ||||
| create_tag | Tag | Create a new tag | | ||||
| delete_tag | Tag | Delete a tag | | ||||
| get_tag | Tag | Get a tag | | ||||
| list_tags | Tag | List all tags in a repository | | ||||
| list_repo_commits | Commit | List all commits in a repository | | ||||
| get_file_content | File | Get the content and metadata of a file | | ||||
| create_file | File | Create a new file | | ||||
|
@@ -154,6 +154,15 @@ Gitea MCP 服务器支持以下工具: | ||||
| create_branch | 分支 | 创建一个新分支 | | ||||
| delete_branch | 分支 | 删除一个分支 | | ||||
| list_branches | 分支 | 列出仓库中的所有分支 | | ||||
| create_release | 版本发布 | 创建一个新版本发布 | | ||||
| delete_release | 版本发布 | 删除一个版本发布 | | ||||
| get_release | 版本发布 | 获取一个版本发布 | | ||||
| get_latest_release | 版本发布 | 获取最新的版本发布 | | ||||
| list_releases | 版本发布 | 列出所有版本发布 | | ||||
| create_tag | 标签 | 创建一个新标签 | | ||||
| delete_tag | 标签 | 删除一个标签 | | ||||
| get_tag | 标签 | 获取一个标签 | | ||||
| list_tags | 标签 | 列出所有标签 | | ||||
| list_repo_commits | 提交 | 列出仓库中的所有提交 | | ||||
| get_file_content | 文件 | 获取文件的内容和元数据 | | ||||
| create_file | 文件 | 创建一个新文件 | | ||||
|
@@ -144,7 +144,6 @@ cp gitea-mcp /usr/local/bin/ | ||||
## ✅ 可用工具 | ||||
| ||||
Gitea MCP 伺服器支持以下工具: | ||||
| ||||
| 工具 | 範圍 | 描述 | | ||||
| :--------------------------: | :------: | :--------------------------: | | ||||
| get_my_user_info | 用戶 | 獲取已認證用戶的信息 | | ||||
@@ -154,6 +153,15 @@ Gitea MCP 伺服器支持以下工具: | ||||
| create_branch | 分支 | 創建一個新分支 | | ||||
| delete_branch | 分支 | 刪除一個分支 | | ||||
| list_branches | 分支 | 列出倉庫中的所有分支 | | ||||
| create_release | 版本發布 | 創建一個新版本發布 | | ||||
| delete_release | 版本發布 | 刪除一個版本發布 | | ||||
| get_release | 版本發布 | 獲取一個版本發布 | | ||||
| get_latest_release | 版本發布 | 獲取最新的版本發布 | | ||||
| list_releases | 版本發布 | 列出所有版本發布 | | ||||
| create_tag | 標籤 | 創建一個新標籤 | | ||||
| delete_tag | 標籤 | 刪除一個標籤 | | ||||
| get_tag | 標籤 | 獲取一個標籤 | | ||||
| list_tags | 標籤 | 列出所有標籤 | | ||||
| list_repo_commits | 提交 | 列出倉庫中的所有提交 | | ||||
| get_file_content | 文件 | 獲取文件的內容和元數據 | | ||||
| create_file | 文件 | 創建一個新文件 | | ||||
|
230 operation/repo/release.go Normal file
230
operation/repo/release.go Normal file @@ -0,0 +1,230 @@ | ||||
package repo | ||||
| ||||
import ( | ||||
"context" | ||||
"fmt" | ||||
"time" | ||||
| ||||
gitea_sdk "code.gitea.io/sdk/gitea" | ||||
"gitea.com/gitea/gitea-mcp/pkg/gitea" | ||||
"gitea.com/gitea/gitea-mcp/pkg/log" | ||||
"gitea.com/gitea/gitea-mcp/pkg/ptr" | ||||
"gitea.com/gitea/gitea-mcp/pkg/to" | ||||
"github.com/mark3labs/mcp-go/mcp" | ||||
) | ||||
| ||||
const ( | ||||
CreateReleaseToolName = "create_release" | ||||
DeleteReleaseToolName = "delete_release" | ||||
GetReleaseToolName = "get_release" | ||||
GetLatestReleaseToolName = "get_latest_release" | ||||
ListReleasesToolName = "list_releases" | ||||
) | ||||
| ||||
var ( | ||||
CreateReleaseTool = mcp.NewTool( | ||||
CreateReleaseToolName, | ||||
mcp.WithDescription("Create 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")), | ||||
mcp.WithString("target", mcp.Required(), mcp.Description("target commitish")), | ||||
mcp.WithString("title", mcp.Required(), mcp.Description("release title")), | ||||
mcp.WithBoolean("is_draft", mcp.Description("Whether the release is draft"), mcp.DefaultBool(false)), | ||||
mcp.WithBoolean("is_pre_release", mcp.Description("Whether the release is pre-release"), mcp.DefaultBool(false)), | ||||
) | ||||
| ||||
DeleteReleaseTool = mcp.NewTool( | ||||
DeleteReleaseToolName, | ||||
mcp.WithDescription("Delete 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")), | ||||
) | ||||
| ||||
GetReleaseTool = mcp.NewTool( | ||||
GetReleaseToolName, | ||||
mcp.WithDescription("Get 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")), | ||||
) | ||||
| ||||
GetLatestReleaseTool = mcp.NewTool( | ||||
GetLatestReleaseToolName, | ||||
mcp.WithDescription("Get latest release"), | ||||
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")), | ||||
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")), | ||||
) | ||||
| ||||
ListReleasesTool = mcp.NewTool( | ||||
ListReleasesToolName, | ||||
mcp.WithDescription("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)), | ||||
mcp.WithBoolean("is_pre_release", mcp.Description("Whether the release is pre-release"), mcp.DefaultBool(false)), | ||||
mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(1), mcp.Min(1)), | ||||
mcp.WithNumber("pageSize", mcp.Description("page size"), mcp.DefaultNumber(20), mcp.Min(1)), | ||||
) | ||||
) | ||||
| ||||
// To avoid return too many tokens, we need to provide at least information as possible | ||||
// llm can call get release to get more information | ||||
type ListReleaseResult struct { | ||||
ID int64 `json:"id"` | ||||
TagName string `json:"tag_name"` | ||||
Target string `json:"target_commitish"` | ||||
Title string `json:"title"` | ||||
IsDraft bool `json:"draft"` | ||||
IsPrerelease bool `json:"prerelease"` | ||||
CreatedAt time.Time `json:"created_at"` | ||||
PublishedAt time.Time `json:"published_at"` | ||||
} | ||||
| ||||
func CreateReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called CreateReleasesFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
tagName, ok := req.Params.Arguments["tag_name"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("tag_name is required") | ||||
} | ||||
target, ok := req.Params.Arguments["target"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("target is required") | ||||
} | ||||
title, ok := req.Params.Arguments["title"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("title is required") | ||||
} | ||||
isDraft, _ := req.Params.Arguments["is_draft"].(bool) | ||||
isPreRelease, _ := req.Params.Arguments["is_pre_release"].(bool) | ||||
| ||||
_, _, err := gitea.Client().CreateRelease(owner, repo, gitea_sdk.CreateReleaseOption{ | ||||
TagName: tagName, | ||||
yp05327 marked this conversation as resolved | ||||
Target: target, | ||||
Title: title, | ||||
IsDraft: isDraft, | ||||
IsPrerelease: isPreRelease, | ||||
}) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("create release error: %v", err) | ||||
} | ||||
| ||||
return mcp.NewToolResultText("Release Created"), nil | ||||
} | ||||
| ||||
func DeleteReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called DeleteReleaseFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
id, ok := req.Params.Arguments["id"].(float64) | ||||
yp05327 marked this conversation as resolved Outdated hiifong commented as above as above | ||||
if !ok { | ||||
return nil, fmt.Errorf("id is required") | ||||
} | ||||
| ||||
_, err := gitea.Client().DeleteRelease(owner, repo, int64(id)) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("delete release error: %v", err) | ||||
} | ||||
| ||||
return to.TextResult("Release deleted successfully") | ||||
} | ||||
| ||||
func GetReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called GetReleaseFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
id, ok := req.Params.Arguments["id"].(float64) | ||||
if !ok { | ||||
return nil, fmt.Errorf("id is required") | ||||
} | ||||
yp05327 marked this conversation as resolved Outdated hiifong commented as above as above | ||||
| ||||
release, _, err := gitea.Client().GetRelease(owner, repo, int64(id)) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("get release error: %v", err) | ||||
} | ||||
| ||||
return to.TextResult(release) | ||||
} | ||||
yp05327 marked this conversation as resolved Outdated hiifong commented Here you should use ptr.To Here you should use ptr.To yp05327 commented d650f8c7ee8cdec99679b88e933b94256da9be5f | ||||
| ||||
func GetLatestReleaseFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called GetLatestReleaseFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
| ||||
release, _, err := gitea.Client().GetLatestRelease(owner, repo) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("get latest release error: %v", err) | ||||
} | ||||
| ||||
return to.TextResult(release) | ||||
} | ||||
| ||||
func ListReleasesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called ListReleasesFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
isDraft, _ := req.Params.Arguments["is_draft"].(bool) | ||||
isPreRelease, _ := req.Params.Arguments["is_pre_release"].(bool) | ||||
page, _ := req.Params.Arguments["page"].(float64) | ||||
pageSize, _ := req.Params.Arguments["pageSize"].(float64) | ||||
| ||||
releases, _, err := gitea.Client().ListReleases(owner, repo, gitea_sdk.ListReleasesOptions{ | ||||
ListOptions: gitea_sdk.ListOptions{ | ||||
Page: int(page), | ||||
PageSize: int(pageSize), | ||||
}, | ||||
IsDraft: ptr.To(isDraft), | ||||
IsPreRelease: ptr.To(isPreRelease), | ||||
}) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("list releases error: %v", err) | ||||
} | ||||
| ||||
results := make([]ListReleaseResult, len(releases)) | ||||
for _, release := range releases { | ||||
results = append(results, ListReleaseResult{ | ||||
ID: release.ID, | ||||
TagName: release.TagName, | ||||
Target: release.Target, | ||||
Title: release.Title, | ||||
IsDraft: release.IsDraft, | ||||
IsPrerelease: release.IsPrerelease, | ||||
CreatedAt: release.CreatedAt, | ||||
PublishedAt: release.PublishedAt, | ||||
}) | ||||
} | ||||
return to.TextResult(results) | ||||
} |
@@ -70,6 +70,19 @@ func RegisterTool(s *server.MCPServer) { | ||||
s.AddTool(DeleteBranchTool, DeleteBranchFn) | ||||
s.AddTool(ListBranchesTool, ListBranchesFn) | ||||
| ||||
// Release | ||||
s.AddTool(CreateReleaseTool, CreateReleaseFn) | ||||
s.AddTool(DeleteReleaseTool, DeleteReleaseFn) | ||||
s.AddTool(GetReleaseTool, GetReleaseFn) | ||||
s.AddTool(GetLatestReleaseTool, GetLatestReleaseFn) | ||||
s.AddTool(ListReleasesTool, ListReleasesFn) | ||||
| ||||
// Tag | ||||
s.AddTool(CreateTagTool, CreateTagFn) | ||||
s.AddTool(DeleteTagTool, DeleteTagFn) | ||||
s.AddTool(GetTagTool, GetTagFn) | ||||
s.AddTool(ListTagsTool, ListTagsFn) | ||||
| ||||
// Commit | ||||
s.AddTool(ListRepoCommitsTool, ListRepoCommitsFn) | ||||
} | ||||
|
174 operation/repo/tag.go Normal file
174
operation/repo/tag.go Normal file @@ -0,0 +1,174 @@ | ||||
package repo | ||||
| ||||
import ( | ||||
"context" | ||||
"fmt" | ||||
| ||||
gitea_sdk "code.gitea.io/sdk/gitea" | ||||
"gitea.com/gitea/gitea-mcp/pkg/gitea" | ||||
"gitea.com/gitea/gitea-mcp/pkg/log" | ||||
"gitea.com/gitea/gitea-mcp/pkg/to" | ||||
"github.com/mark3labs/mcp-go/mcp" | ||||
) | ||||
| ||||
const ( | ||||
CreateTagToolName = "create_tag" | ||||
DeleteTagToolName = "delete_tag" | ||||
GetTagToolName = "get_tag" | ||||
ListTagsToolName = "list_tags" | ||||
) | ||||
| ||||
var ( | ||||
CreateTagTool = mcp.NewTool( | ||||
CreateTagToolName, | ||||
mcp.WithDescription("Create 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")), | ||||
mcp.WithString("target", mcp.Description("target commitish"), mcp.DefaultString("")), | ||||
mcp.WithString("message", mcp.Description("tag message"), mcp.DefaultString("")), | ||||
) | ||||
| ||||
DeleteTagTool = mcp.NewTool( | ||||
DeleteTagToolName, | ||||
mcp.WithDescription("Delete 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")), | ||||
) | ||||
| ||||
GetTagTool = mcp.NewTool( | ||||
GetTagToolName, | ||||
mcp.WithDescription("Get 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")), | ||||
) | ||||
| ||||
ListTagsTool = mcp.NewTool( | ||||
ListTagsToolName, | ||||
mcp.WithDescription("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)), | ||||
mcp.WithNumber("pageSize", mcp.Description("page size"), mcp.DefaultNumber(20), mcp.Min(1)), | ||||
) | ||||
) | ||||
| ||||
// To avoid return too many tokens, we need to provide at least information as possible | ||||
// llm can call get tag to get more information | ||||
type ListTagResult struct { | ||||
ID string `json:"id"` | ||||
Name string `json:"name"` | ||||
Commit *gitea_sdk.CommitMeta `json:"commit"` | ||||
// message may be a long text, so we should not provide it here | ||||
} | ||||
| ||||
func CreateTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called CreateTagFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
tagName, ok := req.Params.Arguments["tag_name"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("tag_name is required") | ||||
} | ||||
target, _ := req.Params.Arguments["target"].(string) | ||||
message, _ := req.Params.Arguments["message"].(string) | ||||
| ||||
_, _, err := gitea.Client().CreateTag(owner, repo, gitea_sdk.CreateTagOption{ | ||||
TagName: tagName, | ||||
Target: target, | ||||
Message: message, | ||||
}) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("create tag error: %v", err) | ||||
} | ||||
| ||||
return mcp.NewToolResultText("Tag Created"), nil | ||||
} | ||||
| ||||
func DeleteTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called DeleteTagFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
tagName, ok := req.Params.Arguments["tag_name"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("tag_name is required") | ||||
} | ||||
| ||||
_, err := gitea.Client().DeleteTag(owner, repo, tagName) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("delete tag error: %v", err) | ||||
} | ||||
| ||||
return to.TextResult("Tag deleted") | ||||
} | ||||
| ||||
func GetTagFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called GetTagFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
tagName, ok := req.Params.Arguments["tag_name"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("tag_name is required") | ||||
} | ||||
| ||||
tag, _, err := gitea.Client().GetTag(owner, repo, tagName) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("get tag error: %v", err) | ||||
} | ||||
| ||||
return to.TextResult(tag) | ||||
} | ||||
| ||||
func ListTagsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { | ||||
log.Debugf("Called ListTagsFn") | ||||
owner, ok := req.Params.Arguments["owner"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("owner is required") | ||||
} | ||||
repo, ok := req.Params.Arguments["repo"].(string) | ||||
if !ok { | ||||
return nil, fmt.Errorf("repo is required") | ||||
} | ||||
page, _ := req.Params.Arguments["page"].(float64) | ||||
pageSize, _ := req.Params.Arguments["pageSize"].(float64) | ||||
| ||||
tags, _, err := gitea.Client().ListRepoTags(owner, repo, gitea_sdk.ListRepoTagsOptions{ | ||||
ListOptions: gitea_sdk.ListOptions{ | ||||
Page: int(page), | ||||
PageSize: int(pageSize), | ||||
}, | ||||
}) | ||||
if err != nil { | ||||
return nil, fmt.Errorf("list tags error: %v", err) | ||||
} | ||||
| ||||
results := make([]ListTagResult, 0, len(tags)) | ||||
for _, tag := range tags { | ||||
results = append(results, ListTagResult{ | ||||
ID: tag.ID, | ||||
Name: tag.Name, | ||||
Commit: tag.Commit, | ||||
}) | ||||
} | ||||
return to.TextResult(results) | ||||
} |
Reference in New Issue
Block a user
It should be asserted here as float64. All assertions of type Number must be float64