228 lines
6.8 KiB
Go
228 lines
6.8 KiB
Go
package stars
|
|
|
|
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.com/gitea/gitea-mcp/pkg/tool"
|
|
|
|
gitea_sdk "code.gitea.io/sdk/gitea"
|
|
"github.com/mark3labs/mcp-go/mcp"
|
|
"github.com/mark3labs/mcp-go/server"
|
|
)
|
|
|
|
var Tool = tool.New()
|
|
|
|
const (
|
|
StarsReadToolName = "stars_read"
|
|
StarsWriteToolName = "stars_write"
|
|
)
|
|
|
|
var (
|
|
StarsReadTool = mcp.NewTool(
|
|
StarsReadToolName,
|
|
mcp.WithDescription("Read stars information. Use method 'list_stargazers' to list repo stargazers, 'list_starred' to list user's starred repos, 'my_starred' for your starred repos, 'check' to check if user starred a repo."),
|
|
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("list_stargazers", "list_starred", "my_starred", "check")),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
|
mcp.WithString("user", mcp.Description("username (for 'list_starred', 'check')")),
|
|
)
|
|
|
|
StarsWriteTool = mcp.NewTool(
|
|
StarsWriteToolName,
|
|
mcp.WithDescription("Star or unstar a repository."),
|
|
mcp.WithString("method", mcp.Required(), mcp.Description("operation to perform"), mcp.Enum("star", "unstar")),
|
|
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
|
|
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
|
|
)
|
|
)
|
|
|
|
func init() {
|
|
Tool.RegisterRead(server.ServerTool{
|
|
Tool: StarsReadTool,
|
|
Handler: starsReadFn,
|
|
})
|
|
Tool.RegisterWrite(server.ServerTool{
|
|
Tool: StarsWriteTool,
|
|
Handler: starsWriteFn,
|
|
})
|
|
}
|
|
|
|
func starsReadFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
method, err := params.GetString(req.GetArguments(), "method")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
switch method {
|
|
case "list_stargazers":
|
|
return listStargazersFn(ctx, req)
|
|
case "list_starred":
|
|
return listStarredFn(ctx, req)
|
|
case "my_starred":
|
|
return myStarredFn(ctx, req)
|
|
case "check":
|
|
return checkStarFn(ctx, req)
|
|
default:
|
|
return to.ErrorResult(fmt.Errorf("unknown method: %s", method))
|
|
}
|
|
}
|
|
|
|
func starsWriteFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
method, err := params.GetString(req.GetArguments(), "method")
|
|
if err != nil {
|
|
return to.ErrorResult(err)
|
|
}
|
|
switch method {
|
|
case "star":
|
|
return starRepoFn(ctx, req)
|
|
case "unstar":
|
|
return unstarRepoFn(ctx, req)
|
|
default:
|
|
return to.ErrorResult(fmt.Errorf("unknown method: %s", method))
|
|
}
|
|
}
|
|
|
|
func listStargazersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called listStargazersFn")
|
|
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)
|
|
}
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
users, _, err := client.ListRepoStargazers(owner, repo, gitea_sdk.ListStargazersOptions{})
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list stargazers err: %v", err))
|
|
}
|
|
return to.TextResult(slimUsers(users))
|
|
}
|
|
|
|
func listStarredFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called listStarredFn")
|
|
user, err := params.GetString(req.GetArguments(), "user")
|
|
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))
|
|
}
|
|
repos, _, err := client.GetStarredRepos(user)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list starred repos err: %v", err))
|
|
}
|
|
return to.TextResult(slimRepos(repos))
|
|
}
|
|
|
|
func myStarredFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called myStarredFn")
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
repos, _, err := client.GetMyStarredRepos()
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("list my starred repos err: %v", err))
|
|
}
|
|
return to.TextResult(slimRepos(repos))
|
|
}
|
|
|
|
func checkStarFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called checkStarFn")
|
|
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)
|
|
}
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
starred, _, err := client.IsRepoStarring(owner, repo)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("check star err: %v", err))
|
|
}
|
|
return to.TextResult(map[string]any{"starred": starred})
|
|
}
|
|
|
|
func starRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called starRepoFn")
|
|
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)
|
|
}
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
_, err = client.StarRepo(owner, repo)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("star repo err: %v", err))
|
|
}
|
|
return to.TextResult("Repository starred successfully")
|
|
}
|
|
|
|
func unstarRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
log.Debugf("Called unstarRepoFn")
|
|
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)
|
|
}
|
|
client, err := gitea.ClientFromContext(ctx)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
|
|
}
|
|
_, err = client.UnStarRepo(owner, repo)
|
|
if err != nil {
|
|
return to.ErrorResult(fmt.Errorf("unstar repo err: %v", err))
|
|
}
|
|
return to.TextResult("Repository unstarred successfully")
|
|
}
|
|
|
|
func slimUsers(users []*gitea_sdk.User) []map[string]any {
|
|
out := make([]map[string]any, 0, len(users))
|
|
for _, u := range users {
|
|
out = append(out, map[string]any{
|
|
"id": u.ID,
|
|
"login": u.UserName,
|
|
"full_name": u.FullName,
|
|
"avatar_url": u.AvatarURL,
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func slimRepos(repos []*gitea_sdk.Repository) []map[string]any {
|
|
out := make([]map[string]any, 0, len(repos))
|
|
for _, r := range repos {
|
|
out = append(out, map[string]any{
|
|
"id": r.ID,
|
|
"name": r.Name,
|
|
"full_name": r.FullName,
|
|
"private": r.Private,
|
|
})
|
|
}
|
|
return out
|
|
}
|