13 Commits

Author SHA1 Message Date
hiifong
2a9504fc5d update (#8)
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/8
2025-03-27 07:31:39 +00:00
hiifong
2f17f37053 fix bug (#7)
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/7
2025-03-27 07:18:51 +00:00
hiifong
5270d2eb08 Adding more logs (#6)
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/6
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: hiifong <i@hiif.ong>
Co-committed-by: hiifong <i@hiif.ong>
2025-03-25 17:22:39 +00:00
Lunny Xiao
97b98c3fc2 Merge pull request 'Add SHA to update file, convert get_file into get_file_content' (#5) from yp05327/gitea-mcp:add-sha-to-update-file into main
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/5
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-03-25 04:30:18 +00:00
hiifong
58328680a6 Merge branch 'main' into add-sha-to-update-file 2025-03-25 04:29:07 +00:00
Lunny Xiao
28947a030e Merge pull request 'Update README' (#4) from yp05327/gitea-mcp:update-readme into main
Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/4
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
2025-03-25 04:28:34 +00:00
yp05327
d48e233fba update readme 2025-03-25 04:26:47 +00:00
yp05327
0e225f21da fix 2025-03-25 04:25:28 +00:00
yp05327
b9e575ad64 fix 2025-03-25 03:42:37 +00:00
yp05327
8395957553 update 2025-03-25 03:11:33 +00:00
yp05327
0aa33e0d62 change the emoji 2025-03-25 03:10:06 +00:00
yp05327
7d2a0985a3 change the emoji 2025-03-25 03:09:12 +00:00
yp05327
6f86512a7d update 2025-03-25 02:56:56 +00:00
12 changed files with 155 additions and 108 deletions

View File

@@ -2,11 +2,13 @@
**Gitea MCP Server** is an integration plugin designed to connect Gitea with Model Context Protocol (MCP) systems. This allows for seamless command execution and repository management through an MCP-compatible chat interface.
## 🚧 Installation
## 🚧Installation
There is currently no official release. You will need to build the Gitea MCP Server from source.
### 📥Download the official binary release
### 🔧 Build from Source
You can download the official release from [here](https://gitea.com/gitea/gitea-mcp/releases).
### 🔧Build from Source
You can download the source code by cloning the repository using Git:
@@ -25,7 +27,7 @@ Then run:
make build
```
### 🛠️ Add to PATH
### 📁Add to PATH
After building, copy the binary gitea-mcp to a directory included in your system's PATH. For example:
@@ -33,12 +35,13 @@ After building, copy the binary gitea-mcp to a directory included in your system
cp gitea-mcp /usr/local/bin/
```
## 🚀 Usage
## 🚀Usage
This example is for Cursor, you can also use plugins in VSCode.
To configure the MCP server for Gitea, add the following to your MCP configuration file:
- **stdio mode**
```json
{
"mcpServers": {
@@ -59,6 +62,7 @@ To configure the MCP server for Gitea, add the following to your MCP configurati
```
- **sse mode**
```json
{
"mcpServers": {
@@ -93,7 +97,7 @@ The Gitea MCP Server supports the following tools:
|delete_branch|Branch|Delete a branch|
|list_branches|Branch|List all branches in a repository|
|list_repo_commits|Commit|List all commits in a repository|
|get_file|File|Get the content of a file|
|get_file_content|File|Get the content and metadata of a file|
|create_file|File|Create a new file|
|update_file|File|Update an existing file|
|delete_file|File|Delete a file|
@@ -109,10 +113,10 @@ The Gitea MCP Server supports the following tools:
|search_repos|Repository|Search for repositories|
|get_gitea_mcp_server_version|Server|Get the version of the Gitea MCP Server|
## 🐛 Debugging
## 🐛Debugging
To enable debug mode, add the `-d` flag when running the Gitea MCP Server with sse mode:
```sh
./gitea-mcp -t sse --token <your personal access token> -d
```

2
go.mod
View File

@@ -4,7 +4,7 @@ go 1.24.0
require (
code.gitea.io/sdk/gitea v0.20.0
github.com/mark3labs/mcp-go v0.15.0
github.com/mark3labs/mcp-go v0.17.0
go.uber.org/zap v1.27.0
)

2
go.sum
View File

@@ -14,6 +14,8 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/mark3labs/mcp-go v0.15.0 h1:lViiC4dk6chJHZccezaTzZLMOQVUXJDGNQPtzExr5NQ=
github.com/mark3labs/mcp-go v0.15.0/go.mod h1:xBB350hekQsJAK7gJAii8bcEoWemboLm2mRm5/+KBaU=
github.com/mark3labs/mcp-go v0.17.0 h1:5Ps6T7qXr7De/2QTqs9h6BKeZ/qdeUeGrgM5lPzi930=
github.com/mark3labs/mcp-go v0.17.0/go.mod h1:KmJndYv7GIgcPVwEKJjNcbhVQ+hJGJhrCCB/9xITzpE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=

View File

@@ -68,19 +68,19 @@ func GetIssueByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
log.Debugf("Called GetIssueByIndexFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
index, ok := req.Params.Arguments["index"].(float64)
if !ok {
return nil, fmt.Errorf("index is required")
return to.ErrorResult(fmt.Errorf("index is required"))
}
issue, _, err := gitea.Client().GetIssue(owner, repo, int64(index))
if err != nil {
return nil, fmt.Errorf("get %v/%v/issue/%v err", owner, repo, int64(index))
return to.ErrorResult(fmt.Errorf("get %v/%v/issue/%v err: %v", owner, repo, int64(index), err))
}
return to.TextResult(issue)
@@ -90,11 +90,11 @@ func ListRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
log.Debugf("Called ListIssuesFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
state, ok := req.Params.Arguments["state"].(string)
if !ok {
@@ -117,7 +117,7 @@ func ListRepoIssuesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
}
issues, _, err := gitea.Client().ListRepoIssues(owner, repo, opt)
if err != nil {
return nil, fmt.Errorf("get %v/%v/issues err", owner, repo)
return to.ErrorResult(fmt.Errorf("get %v/%v/issues err: %v", owner, repo, err))
}
return to.TextResult(issues)
}
@@ -126,26 +126,26 @@ func CreateIssueFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
log.Debugf("Called CreateIssueFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
title, ok := req.Params.Arguments["title"].(string)
if !ok {
return nil, fmt.Errorf("title is required")
return to.ErrorResult(fmt.Errorf("title is required"))
}
body, ok := req.Params.Arguments["body"].(string)
if !ok {
return nil, fmt.Errorf("body is required")
return to.ErrorResult(fmt.Errorf("body is required"))
}
issue, _, err := gitea.Client().CreateIssue(owner, repo, gitea_sdk.CreateIssueOption{
Title: title,
Body: body,
})
if err != nil {
return nil, fmt.Errorf("create %v/%v/issue err", owner, repo)
return to.ErrorResult(fmt.Errorf("create %v/%v/issue err", owner, repo))
}
return to.TextResult(issue)
@@ -155,26 +155,26 @@ func CreateIssueCommentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
log.Debugf("Called CreateIssueCommentFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
index, ok := req.Params.Arguments["index"].(float64)
if !ok {
return nil, fmt.Errorf("index is required")
return to.ErrorResult(fmt.Errorf("index is required"))
}
body, ok := req.Params.Arguments["body"].(string)
if !ok {
return nil, fmt.Errorf("body is required")
return to.ErrorResult(fmt.Errorf("body is required"))
}
opt := gitea_sdk.CreateIssueCommentOption{
Body: body,
}
issueComment, _, err := gitea.Client().CreateIssueComment(owner, repo, int64(index), opt)
if err != nil {
return nil, fmt.Errorf("create %v/%v/issue/%v/comment err", owner, repo, int64(index))
return to.ErrorResult(fmt.Errorf("create %v/%v/issue/%v/comment err", owner, repo, int64(index)))
}
return to.TextResult(issueComment)

View File

@@ -33,9 +33,11 @@ var (
mcp.WithDescription("List repository 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.WithString("sort", mcp.Description("sort")),
mcp.WithString("state", mcp.Description("state"), mcp.Enum("open", "closed", "all"), mcp.DefaultString("all")),
mcp.WithString("sort", mcp.Description("sort"), mcp.Enum("oldest", "recentupdate", "leastupdate", "mostcomment", "leastcomment", "priority"), mcp.DefaultString("recentupdate")),
mcp.WithNumber("milestone", mcp.Description("milestone")),
mcp.WithNumber("page", mcp.Description("page number"), mcp.DefaultNumber(1)),
mcp.WithNumber("pageSize", mcp.Description("page size"), mcp.DefaultNumber(100)),
)
CreatePullRequestTool = mcp.NewTool(
@@ -60,19 +62,19 @@ func GetPullRequestByIndexFn(ctx context.Context, req mcp.CallToolRequest) (*mcp
log.Debugf("Called GetPullRequestByIndexFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
index, ok := req.Params.Arguments["index"].(float64)
if !ok {
return nil, fmt.Errorf("index is required")
return to.ErrorResult(fmt.Errorf("index is required"))
}
pr, _, err := gitea.Client().GetPullRequest(owner, repo, int64(index))
if err != nil {
return nil, fmt.Errorf("get %v/%v/pr/%v err", owner, repo, int64(index))
return to.ErrorResult(fmt.Errorf("get %v/%v/pr/%v err: %v", owner, repo, int64(index), err))
}
return to.TextResult(pr)
@@ -82,27 +84,38 @@ func ListRepoPullRequestsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.
log.Debugf("Called ListRepoPullRequests")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
state, _ := req.Params.Arguments["state"].(string)
sort, _ := req.Params.Arguments["sort"].(string)
sort, ok := req.Params.Arguments["sort"].(string)
if !ok {
sort = "recentupdate"
}
milestone, _ := req.Params.Arguments["milestone"].(float64)
page, ok := req.Params.Arguments["page"].(float64)
if !ok {
page = 1
}
pageSize, ok := req.Params.Arguments["pageSize"].(float64)
if !ok {
pageSize = 100
}
opt := gitea_sdk.ListPullRequestsOptions{
State: gitea_sdk.StateType(state),
Sort: sort,
Milestone: int64(milestone),
ListOptions: gitea_sdk.ListOptions{
Page: 1,
PageSize: 1000,
Page: int(page),
PageSize: int(pageSize),
},
}
pullRequests, _, err := gitea.Client().ListRepoPullRequests("", "", opt)
pullRequests, _, err := gitea.Client().ListRepoPullRequests(owner, repo, opt)
if err != nil {
return nil, fmt.Errorf("list %v/%v/pull_requests err", owner, repo)
return to.ErrorResult(fmt.Errorf("list %v/%v/pull_requests err: %v", owner, repo, err))
}
return to.TextResult(pullRequests)
@@ -112,27 +125,27 @@ func CreatePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
log.Debugf("Called CreatePullRequestFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
title, ok := req.Params.Arguments["title"].(string)
if !ok {
return nil, fmt.Errorf("title is required")
return to.ErrorResult(fmt.Errorf("title is required"))
}
body, ok := req.Params.Arguments["body"].(string)
if !ok {
return nil, fmt.Errorf("body is required")
return to.ErrorResult(fmt.Errorf("body is required"))
}
head, ok := req.Params.Arguments["head"].(string)
if !ok {
return nil, fmt.Errorf("head is required")
return to.ErrorResult(fmt.Errorf("head is required"))
}
base, ok := req.Params.Arguments["base"].(string)
if !ok {
return nil, fmt.Errorf("base is required")
return to.ErrorResult(fmt.Errorf("base is required"))
}
pr, _, err := gitea.Client().CreatePullRequest(owner, repo, gitea_sdk.CreatePullRequestOption{
Title: title,
@@ -141,7 +154,7 @@ func CreatePullRequestFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.Cal
Base: base,
})
if err != nil {
return nil, fmt.Errorf("create %v/%v/pull_request err", owner, repo)
return to.ErrorResult(fmt.Errorf("create %v/%v/pull_request err: %v", owner, repo, err))
}
return to.TextResult(pr)

View File

@@ -48,15 +48,15 @@ func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
log.Debugf("Called CreateBranchFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
branch, ok := req.Params.Arguments["branch"].(string)
if !ok {
return nil, fmt.Errorf("branch is required")
return to.ErrorResult(fmt.Errorf("branch is required"))
}
oldBranch, _ := req.Params.Arguments["old_branch"].(string)
@@ -65,7 +65,7 @@ func CreateBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
OldBranchName: oldBranch,
})
if err != nil {
return nil, fmt.Errorf("Create Branch Error: %v", err)
return to.ErrorResult(fmt.Errorf("create branch error: %v", err))
}
return mcp.NewToolResultText("Branch Created"), nil
@@ -75,19 +75,19 @@ func DeleteBranchFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
log.Debugf("Called DeleteBranchFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
branch, ok := req.Params.Arguments["branch"].(string)
if !ok {
return nil, fmt.Errorf("branch is required")
return to.ErrorResult(fmt.Errorf("branch is required"))
}
_, _, err := gitea.Client().DeleteRepoBranch(owner, repo, branch)
if err != nil {
return nil, fmt.Errorf("Delete Branch Error: %v", err)
return to.ErrorResult(fmt.Errorf("delete branch error: %v", err))
}
return to.TextResult("Branch Deleted")
@@ -97,11 +97,11 @@ func ListBranchesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
log.Debugf("Called ListBranchesFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
opt := gitea_sdk.ListRepoBranchesOptions{
ListOptions: gitea_sdk.ListOptions{
@@ -111,7 +111,7 @@ func ListBranchesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTool
}
branches, _, err := gitea.Client().ListRepoBranches(owner, repo, opt)
if err != nil {
return nil, fmt.Errorf("List Branches Error: %v", err)
return to.ErrorResult(fmt.Errorf("list branches error: %v", err))
}
return to.TextResult(branches)

View File

@@ -22,8 +22,10 @@ var (
mcp.WithDescription("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")),
mcp.WithString("path", mcp.Description("path")),
mcp.WithString("sha", mcp.Description("SHA or branch to start listing commits from")),
mcp.WithString("path", mcp.Description("path indicates that only commits that include the path's file/dir should be returned.")),
mcp.WithNumber("page", mcp.Required(), mcp.Description("page number"), mcp.DefaultNumber(1), mcp.Min(1)),
mcp.WithNumber("page_size", mcp.Required(), mcp.Description("page size"), mcp.DefaultNumber(50), mcp.Min(1)),
)
)
@@ -31,25 +33,33 @@ func ListRepoCommitsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallT
log.Debugf("Called ListRepoCommitsFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
page, ok := req.Params.Arguments["page"].(float64)
if !ok {
return to.ErrorResult(fmt.Errorf("page is required"))
}
pageSize, ok := req.Params.Arguments["page_size"].(float64)
if !ok {
return to.ErrorResult(fmt.Errorf("page_size is required"))
}
sha, _ := req.Params.Arguments["sha"].(string)
path, _ := req.Params.Arguments["path"].(string)
opt := gitea_sdk.ListCommitOptions{
ListOptions: gitea_sdk.ListOptions{
Page: 1,
PageSize: 1000,
Page: int(page),
PageSize: int(pageSize),
},
SHA: sha,
Path: path,
}
commits, _, err := gitea.Client().ListRepoCommits(owner, repo, opt)
if err != nil {
return nil, fmt.Errorf("list repo commits err: %v", err)
return to.ErrorResult(fmt.Errorf("list repo commits err: %v", err))
}
return to.TextResult(commits)
}

View File

@@ -2,6 +2,7 @@ package repo
import (
"context"
"encoding/base64"
"fmt"
"gitea.com/gitea/gitea-mcp/pkg/gitea"
@@ -13,19 +14,19 @@ import (
)
const (
GetFileToolName = "get_file"
GetFileToolName = "get_file_content"
CreateFileToolName = "create_file"
UpdateFileToolName = "update_file"
DeleteFileToolName = "delete_file"
)
var (
GetFileTool = mcp.NewTool(
GetFileContentTool = mcp.NewTool(
GetFileToolName,
mcp.WithDescription("Get file"),
mcp.WithDescription("Get file Content and Metadata"),
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")),
mcp.WithString("ref", mcp.Required(), mcp.Description("ref can be branch/tag/commit")),
mcp.WithString("filePath", mcp.Required(), mcp.Description("file path")),
)
@@ -47,7 +48,8 @@ var (
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")),
mcp.WithString("content", mcp.Required(), mcp.Description("file content")),
mcp.WithString("sha", mcp.Required(), mcp.Description("sha is the SHA for the file that already exists")),
mcp.WithString("content", mcp.Required(), mcp.Description("file content, base64 encoded")),
mcp.WithString("message", mcp.Required(), mcp.Description("commit message")),
mcp.WithString("branch_name", mcp.Required(), mcp.Description("branch name")),
)
@@ -64,47 +66,47 @@ var (
)
)
func GetFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
func GetFileContentFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called GetFileFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
ref, _ := req.Params.Arguments["ref"].(string)
filePath, ok := req.Params.Arguments["filePath"].(string)
if !ok {
return nil, fmt.Errorf("filePath is required")
return to.ErrorResult(fmt.Errorf("filePath is required"))
}
file, _, err := gitea.Client().GetFile(owner, repo, ref, filePath)
content, _, err := gitea.Client().GetContents(owner, repo, ref, filePath)
if err != nil {
return nil, fmt.Errorf("get file err: %v", err)
return to.ErrorResult(fmt.Errorf("get file err: %v", err))
}
return to.TextResult(file)
return to.TextResult(content)
}
func CreateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CreateFileFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
filePath, ok := req.Params.Arguments["filePath"].(string)
if !ok {
return nil, fmt.Errorf("filePath is required")
return to.ErrorResult(fmt.Errorf("filePath is required"))
}
content, _ := req.Params.Arguments["content"].(string)
message, _ := req.Params.Arguments["message"].(string)
branchName, _ := req.Params.Arguments["branch_name"].(string)
opt := gitea_sdk.CreateFileOptions{
Content: content,
Content: base64.StdEncoding.EncodeToString([]byte(content)),
FileOptions: gitea_sdk.FileOptions{
Message: message,
BranchName: branchName,
@@ -113,7 +115,7 @@ func CreateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
_, _, err := gitea.Client().CreateFile(owner, repo, filePath, opt)
if err != nil {
return nil, fmt.Errorf("create file err: %v", err)
return to.ErrorResult(fmt.Errorf("create file err: %v", err))
}
return to.TextResult("Create file success")
}
@@ -122,20 +124,26 @@ func UpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
log.Debugf("Called UpdateFileFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
filePath, ok := req.Params.Arguments["filePath"].(string)
if !ok {
return nil, fmt.Errorf("filePath is required")
return to.ErrorResult(fmt.Errorf("filePath is required"))
}
sha, ok := req.Params.Arguments["sha"].(string)
if !ok {
return to.ErrorResult(fmt.Errorf("sha is required"))
}
content, _ := req.Params.Arguments["content"].(string)
message, _ := req.Params.Arguments["message"].(string)
branchName, _ := req.Params.Arguments["branch_name"].(string)
opt := gitea_sdk.UpdateFileOptions{
SHA: sha,
Content: content,
FileOptions: gitea_sdk.FileOptions{
Message: message,
@@ -144,7 +152,7 @@ func UpdateFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
}
_, _, err := gitea.Client().UpdateFile(owner, repo, filePath, opt)
if err != nil {
return nil, fmt.Errorf("update file err: %v", err)
return to.ErrorResult(fmt.Errorf("update file err: %v", err))
}
return to.TextResult("Update file success")
}
@@ -153,27 +161,32 @@ func DeleteFileFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
log.Debugf("Called DeleteFileFn")
owner, ok := req.Params.Arguments["owner"].(string)
if !ok {
return nil, fmt.Errorf("owner is required")
return to.ErrorResult(fmt.Errorf("owner is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, fmt.Errorf("repo is required")
return to.ErrorResult(fmt.Errorf("repo is required"))
}
filePath, ok := req.Params.Arguments["filePath"].(string)
if !ok {
return nil, fmt.Errorf("filePath is required")
return to.ErrorResult(fmt.Errorf("filePath is required"))
}
message, _ := req.Params.Arguments["message"].(string)
branchName, _ := req.Params.Arguments["branch_name"].(string)
sha, ok := req.Params.Arguments["sha"].(string)
if !ok {
return to.ErrorResult(fmt.Errorf("sha is required"))
}
opt := gitea_sdk.DeleteFileOptions{
FileOptions: gitea_sdk.FileOptions{
Message: message,
BranchName: branchName,
},
SHA: sha,
}
_, err := gitea.Client().DeleteFile(owner, repo, filePath, opt)
if err != nil {
return nil, fmt.Errorf("delete file err: %v", err)
return to.ErrorResult(fmt.Errorf("delete file err: %v", err))
}
return to.TextResult("Delete file success")
}

View File

@@ -60,7 +60,7 @@ func RegisterTool(s *server.MCPServer) {
s.AddTool(ListMyReposTool, ListMyReposFn)
// File
s.AddTool(GetFileTool, GetFileFn)
s.AddTool(GetFileContentTool, GetFileContentFn)
s.AddTool(CreateFileTool, CreateFileFn)
s.AddTool(UpdateFileTool, UpdateFileFn)
s.AddTool(DeleteFileTool, DeleteFileFn)
@@ -78,7 +78,7 @@ func CreateRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
log.Debugf("Called CreateRepoFn")
name, ok := req.Params.Arguments["name"].(string)
if !ok {
return nil, errors.New("repository name is required")
return to.ErrorResult(errors.New("repository name is required"))
}
description, _ := req.Params.Arguments["description"].(string)
private, _ := req.Params.Arguments["private"].(bool)
@@ -104,7 +104,7 @@ func CreateRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
}
repo, _, err := gitea.Client().CreateRepo(opt)
if err != nil {
return nil, err
return to.ErrorResult(fmt.Errorf("create repo err: %v", err))
}
return to.TextResult(repo)
}
@@ -113,11 +113,11 @@ func ForkRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu
log.Debugf("Called ForkRepoFn")
user, ok := req.Params.Arguments["user"].(string)
if !ok {
return nil, errors.New("user name is required")
return to.ErrorResult(errors.New("user name is required"))
}
repo, ok := req.Params.Arguments["repo"].(string)
if !ok {
return nil, errors.New("repository name is required")
return to.ErrorResult(errors.New("repository name is required"))
}
organization, _ := req.Params.Arguments["organization"].(string)
name, _ := req.Params.Arguments["name"].(string)
@@ -127,7 +127,7 @@ func ForkRepoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResu
}
_, _, err := gitea.Client().CreateFork(user, repo, opt)
if err != nil {
return nil, fmt.Errorf("fork repository error %v", err)
return to.ErrorResult(fmt.Errorf("fork repository error %v", err))
}
return to.TextResult("Fork success")
}
@@ -136,21 +136,21 @@ func ListMyReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
log.Debugf("Called ListMyReposFn")
page, ok := req.Params.Arguments["page"].(float64)
if !ok {
return nil, errors.New("get page number error")
page = 1
}
size, ok := req.Params.Arguments["pageSize"].(float64)
pageSize, ok := req.Params.Arguments["pageSize"].(float64)
if !ok {
return nil, errors.New("get page size number error")
pageSize = 100
}
opt := gitea_sdk.ListReposOptions{
ListOptions: gitea_sdk.ListOptions{
Page: int(page),
PageSize: int(size),
PageSize: int(pageSize),
},
}
repos, _, err := gitea.Client().ListMyRepos(opt)
if err != nil {
return nil, fmt.Errorf("list my repositories error %v", err)
return to.ErrorResult(fmt.Errorf("list my repositories error: %v", err))
}
return to.TextResult(repos)

View File

@@ -65,7 +65,7 @@ func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
log.Debugf("Called SearchUsersFn")
keyword, ok := req.Params.Arguments["keyword"].(string)
if !ok {
return nil, fmt.Errorf("keyword is required")
return to.ErrorResult(fmt.Errorf("keyword is required"))
}
page, ok := req.Params.Arguments["page"].(float64)
if !ok {
@@ -84,7 +84,7 @@ func SearchUsersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
}
users, _, err := gitea.Client().SearchUsers(opt)
if err != nil {
return nil, err
return to.ErrorResult(fmt.Errorf("search users err: %v", err))
}
return to.TextResult(users)
}
@@ -93,11 +93,11 @@ func SearchOrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
log.Debugf("Called SearchOrgTeamsFn")
org, ok := req.Params.Arguments["org"].(string)
if !ok {
return nil, fmt.Errorf("organization is required")
return to.ErrorResult(fmt.Errorf("organization is required"))
}
query, ok := req.Params.Arguments["query"].(string)
if !ok {
return nil, fmt.Errorf("query is required")
return to.ErrorResult(fmt.Errorf("query is required"))
}
includeDescription, _ := req.Params.Arguments["includeDescription"].(bool)
page, ok := req.Params.Arguments["page"].(float64)
@@ -118,7 +118,7 @@ func SearchOrgTeamsFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallTo
}
teams, _, err := gitea.Client().SearchOrgTeams(org, &opt)
if err != nil {
return nil, fmt.Errorf("search organization teams error: %v", err)
return to.ErrorResult(fmt.Errorf("search organization teams error: %v", err))
}
return to.TextResult(teams)
}
@@ -127,7 +127,7 @@ func SearchReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
log.Debugf("Called SearchReposFn")
keyword, ok := req.Params.Arguments["keyword"].(string)
if !ok {
return nil, fmt.Errorf("keyword is required")
return to.ErrorResult(fmt.Errorf("keyword is required"))
}
keywordIsTopic, _ := req.Params.Arguments["keywordIsTopic"].(bool)
keywordInDescription, _ := req.Params.Arguments["keywordInDescription"].(bool)
@@ -160,7 +160,7 @@ func SearchReposFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
}
repos, _, err := gitea.Client().SearchRepos(opt)
if err != nil {
return nil, fmt.Errorf("search repos error: %v", err)
return to.ErrorResult(fmt.Errorf("search repos error: %v", err))
}
return to.TextResult(repos)
}

View File

@@ -31,7 +31,7 @@ func GetUserInfoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolR
log.Debugf("Called GetUserInfoFn")
user, _, err := gitea.Client().GetMyUserInfo()
if err != nil {
return nil, fmt.Errorf("get user info err: %v", err)
return to.ErrorResult(fmt.Errorf("get user info err: %v", err))
}
return to.TextResult(user)

View File

@@ -21,3 +21,8 @@ func TextResult(v any) (*mcp.CallToolResult, error) {
log.Debugf("Text Result: %s", string(resultBytes))
return mcp.NewToolResultText(string(resultBytes)), nil
}
func ErrorResult(err error) (*mcp.CallToolResult, error) {
log.Errorf(err.Error())
return nil, err
}