Initial commit: Gitea MCP Server

This commit is contained in:
2026-04-10 21:57:19 -07:00
commit 1f27844dce
119 changed files with 25001 additions and 0 deletions
+208
View File
@@ -0,0 +1,208 @@
package deploykey
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"
)
const (
ListDeployKeysToolName = "list_deploy_keys"
GetDeployKeyToolName = "get_deploy_key"
CreateDeployKeyToolName = "create_deploy_key"
DeleteDeployKeyToolName = "delete_deploy_key"
)
var Tool = tool.New()
var (
ListDeployKeysTool = mcp.NewTool(
ListDeployKeysToolName,
mcp.WithDescription("List deploy keys for a repository"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
)
GetDeployKeyTool = mcp.NewTool(
GetDeployKeyToolName,
mcp.WithDescription("Get a specific deploy key by ID"),
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("Deploy key ID")),
)
CreateDeployKeyTool = mcp.NewTool(
CreateDeployKeyToolName,
mcp.WithDescription("Create a new deploy key for a repository"),
mcp.WithString("owner", mcp.Required(), mcp.Description("repository owner")),
mcp.WithString("repo", mcp.Required(), mcp.Description("repository name")),
mcp.WithString("title", mcp.Required(), mcp.Description("Title/description for the deploy key")),
mcp.WithString("key", mcp.Required(), mcp.Description("The SSH public key content")),
mcp.WithBoolean("readOnly", mcp.Description("Whether the key is read-only"), mcp.DefaultBool(false)),
)
DeleteDeployKeyTool = mcp.NewTool(
DeleteDeployKeyToolName,
mcp.WithDescription("Delete a deploy key"),
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("Deploy key ID to delete")),
)
)
func init() {
Tool.RegisterRead(server.ServerTool{
Tool: ListDeployKeysTool,
Handler: listDeployKeysFn,
})
Tool.RegisterRead(server.ServerTool{
Tool: GetDeployKeyTool,
Handler: getDeployKeyFn,
})
Tool.RegisterWrite(server.ServerTool{
Tool: CreateDeployKeyTool,
Handler: createDeployKeyFn,
})
Tool.RegisterWrite(server.ServerTool{
Tool: DeleteDeployKeyTool,
Handler: deleteDeployKeyFn,
})
}
func listDeployKeysFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[DeployKey] Called listDeployKeysFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "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))
}
keys, _, err := client.ListDeployKeys(owner, repo, gitea_sdk.ListDeployKeysOptions{})
if err != nil {
return to.ErrorResult(fmt.Errorf("list deploy keys err: %v", err))
}
return to.TextResult(slimDeployKeys(keys))
}
func getDeployKeyFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[DeployKey] Called getDeployKeyFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
id, err := params.GetIndex(args, "id")
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))
}
key, _, err := client.GetDeployKey(owner, repo, id)
if err != nil {
return to.ErrorResult(fmt.Errorf("get deploy key err: %v", err))
}
return to.TextResult(slimDeployKey(key))
}
func createDeployKeyFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[DeployKey] Called createDeployKeyFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
title, err := params.GetString(args, "title")
if err != nil {
return to.ErrorResult(err)
}
key, err := params.GetString(args, "key")
if err != nil {
return to.ErrorResult(err)
}
readOnly, _ := args["readOnly"].(bool)
client, err := gitea.ClientFromContext(ctx)
if err != nil {
return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err))
}
createOpt := gitea_sdk.CreateKeyOption{
Title: title,
Key: key,
ReadOnly: readOnly,
}
respKey, _, err := client.CreateDeployKey(owner, repo, createOpt)
if err != nil {
return to.ErrorResult(fmt.Errorf("create deploy key err: %v", err))
}
return to.TextResult(slimDeployKey(respKey))
}
func deleteDeployKeyFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("[DeployKey] Called deleteDeployKeyFn")
args := req.GetArguments()
owner, err := params.GetString(args, "owner")
if err != nil {
return to.ErrorResult(err)
}
repo, err := params.GetString(args, "repo")
if err != nil {
return to.ErrorResult(err)
}
id, err := params.GetIndex(args, "id")
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.DeleteDeployKey(owner, repo, id)
if err != nil {
return to.ErrorResult(fmt.Errorf("delete deploy key err: %v", err))
}
return to.TextResult("Deploy key deleted successfully")
}
func slimDeployKeys(keys []*gitea_sdk.DeployKey) []map[string]interface{} {
result := make([]map[string]interface{}, len(keys))
for i, k := range keys {
result[i] = slimDeployKey(k)
}
return result
}
func slimDeployKey(k *gitea_sdk.DeployKey) map[string]interface{} {
return map[string]interface{}{
"id": k.ID,
"key": k.Key,
"title": k.Title,
"created": k.Created,
"fingerprint": k.Fingerprint,
"read_only": k.ReadOnly,
}
}