package miscellaneous import ( "context" "errors" "fmt" "git.lethalbits.com/lethalbits/gitea-mcp/pkg/gitea" "git.lethalbits.com/lethalbits/gitea-mcp/pkg/log" "git.lethalbits.com/lethalbits/gitea-mcp/pkg/to" "git.lethalbits.com/lethalbits/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 ( GetServerVersionToolName = "get_server_version" ListGitignoreTemplatesToolName = "list_gitignore_templates" GetGitignoreTemplateToolName = "get_gitignore_template" ListLabelTemplatesToolName = "list_label_templates" GetLabelTemplateToolName = "get_label_template" ListLicenseTemplatesToolName = "list_license_templates" GetLicenseTemplateToolName = "get_license_template" RenderMarkdownToolName = "render_markdown" RenderMarkupToolName = "render_markup" GetNodeInfoToolName = "get_node_info" GetSigningKeyGPGToolName = "get_signing_key_gpg" GetSigningKeySSHToolName = "get_signing_key_ssh" ) var ( GetServerVersionTool = mcp.NewTool( GetServerVersionToolName, mcp.WithDescription("Get the Gitea server version"), ) ListGitignoreTemplatesTool = mcp.NewTool( ListGitignoreTemplatesToolName, mcp.WithDescription("List available .gitignore templates"), ) GetGitignoreTemplateTool = mcp.NewTool( GetGitignoreTemplateToolName, mcp.WithDescription("Get the content of a .gitignore template by name"), mcp.WithString("name", mcp.Required(), mcp.Description("template name (e.g., Go, Python, Node)")), ) ListLabelTemplatesTool = mcp.NewTool( ListLabelTemplatesToolName, mcp.WithDescription("List available label templates"), ) GetLabelTemplateTool = mcp.NewTool( GetLabelTemplateToolName, mcp.WithDescription("Get the labels from a label template"), mcp.WithString("name", mcp.Required(), mcp.Description("template name")), ) ListLicenseTemplatesTool = mcp.NewTool( ListLicenseTemplatesToolName, mcp.WithDescription("List available license templates"), ) GetLicenseTemplateTool = mcp.NewTool( GetLicenseTemplateToolName, mcp.WithDescription("Get the content of a license template"), mcp.WithString("name", mcp.Required(), mcp.Description("license name (e.g., MIT, GPL-3.0, Apache-2.0)")), ) RenderMarkdownTool = mcp.NewTool( RenderMarkdownToolName, mcp.WithDescription("Render markdown text to HTML"), mcp.WithString("text", mcp.Required(), mcp.Description("markdown text to render")), mcp.WithString("mode", mcp.Description("render mode: markdown, gfm, comment (default: markdown)")), mcp.WithString("context", mcp.Description("context for relative links (owner/repo format)")), mcp.WithBoolean("wiki", mcp.Description("treat text as wiki content")), ) RenderMarkupTool = mcp.NewTool( RenderMarkupToolName, mcp.WithDescription("Render markup content to HTML (supports multiple markup languages)"), mcp.WithString("text", mcp.Required(), mcp.Description("markup text to render")), mcp.WithString("mode", mcp.Description("render mode")), mcp.WithString("context", mcp.Description("context for relative links (owner/repo format)")), mcp.WithString("filepath", mcp.Description("file path to determine markup language")), mcp.WithBoolean("wiki", mcp.Description("treat text as wiki content")), ) GetNodeInfoTool = mcp.NewTool( GetNodeInfoToolName, mcp.WithDescription("Get the NodeInfo of the Gitea instance (federation metadata)"), ) GetSigningKeyGPGTool = mcp.NewTool( GetSigningKeyGPGToolName, mcp.WithDescription("Get the GPG signing key of the Gitea instance"), ) GetSigningKeySSHTool = mcp.NewTool( GetSigningKeySSHToolName, mcp.WithDescription("Get the SSH signing key of the Gitea instance"), ) ) func init() { Tool.RegisterRead(server.ServerTool{Tool: GetServerVersionTool, Handler: GetServerVersionFn}) Tool.RegisterRead(server.ServerTool{Tool: ListGitignoreTemplatesTool, Handler: ListGitignoreTemplatesFn}) Tool.RegisterRead(server.ServerTool{Tool: GetGitignoreTemplateTool, Handler: GetGitignoreTemplateFn}) Tool.RegisterRead(server.ServerTool{Tool: ListLabelTemplatesTool, Handler: ListLabelTemplatesFn}) Tool.RegisterRead(server.ServerTool{Tool: GetLabelTemplateTool, Handler: GetLabelTemplateFn}) Tool.RegisterRead(server.ServerTool{Tool: ListLicenseTemplatesTool, Handler: ListLicenseTemplatesFn}) Tool.RegisterRead(server.ServerTool{Tool: GetLicenseTemplateTool, Handler: GetLicenseTemplateFn}) Tool.RegisterRead(server.ServerTool{Tool: GetNodeInfoTool, Handler: GetNodeInfoFn}) Tool.RegisterRead(server.ServerTool{Tool: GetSigningKeyGPGTool, Handler: GetSigningKeyGPGFn}) Tool.RegisterRead(server.ServerTool{Tool: GetSigningKeySSHTool, Handler: GetSigningKeySSHFn}) Tool.RegisterWrite(server.ServerTool{Tool: RenderMarkdownTool, Handler: RenderMarkdownFn}) Tool.RegisterWrite(server.ServerTool{Tool: RenderMarkupTool, Handler: RenderMarkupFn}) } func GetServerVersionFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called GetServerVersionFn") client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } version, _, err := client.ServerVersion() if err != nil { return to.ErrorResult(fmt.Errorf("get server version err: %v", err)) } return to.TextResult(map[string]string{"version": version}) } func ListGitignoreTemplatesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called ListGitignoreTemplatesFn") client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } templates, _, err := client.ListGitignoresTemplates() if err != nil { return to.ErrorResult(fmt.Errorf("list gitignore templates err: %v", err)) } return to.TextResult(templates) } func GetGitignoreTemplateFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called GetGitignoreTemplateFn") name, _ := req.GetArguments()["name"].(string) if name == "" { return to.ErrorResult(errors.New("name is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } info, _, err := client.GetGitignoreTemplateInfo(name) if err != nil { return to.ErrorResult(fmt.Errorf("get gitignore template err: %v", err)) } return to.TextResult(info) } func ListLabelTemplatesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called ListLabelTemplatesFn") client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } templates, _, err := client.ListLabelTemplates() if err != nil { return to.ErrorResult(fmt.Errorf("list label templates err: %v", err)) } return to.TextResult(templates) } func GetLabelTemplateFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called GetLabelTemplateFn") name, _ := req.GetArguments()["name"].(string) if name == "" { return to.ErrorResult(errors.New("name is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } labels, _, err := client.GetLabelTemplate(name) if err != nil { return to.ErrorResult(fmt.Errorf("get label template err: %v", err)) } return to.TextResult(labels) } func ListLicenseTemplatesFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called ListLicenseTemplatesFn") client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } templates, _, err := client.ListLicenseTemplates() if err != nil { return to.ErrorResult(fmt.Errorf("list license templates err: %v", err)) } return to.TextResult(templates) } func GetLicenseTemplateFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called GetLicenseTemplateFn") name, _ := req.GetArguments()["name"].(string) if name == "" { return to.ErrorResult(errors.New("name is required")) } client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } info, _, err := client.GetLicenseTemplateInfo(name) if err != nil { return to.ErrorResult(fmt.Errorf("get license template err: %v", err)) } return to.TextResult(info) } func RenderMarkdownFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called RenderMarkdownFn") text, _ := req.GetArguments()["text"].(string) if text == "" { return to.ErrorResult(errors.New("text is required")) } opt := gitea_sdk.MarkdownOption{ Text: text, } if v, ok := req.GetArguments()["mode"].(string); ok { opt.Mode = v } if v, ok := req.GetArguments()["context"].(string); ok { opt.Context = v } if v, ok := req.GetArguments()["wiki"].(bool); ok { opt.Wiki = v } client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } html, _, err := client.RenderMarkdown(opt) if err != nil { return to.ErrorResult(fmt.Errorf("render markdown err: %v", err)) } return to.TextResult(map[string]string{"html": html}) } func RenderMarkupFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called RenderMarkupFn") text, _ := req.GetArguments()["text"].(string) if text == "" { return to.ErrorResult(errors.New("text is required")) } opt := gitea_sdk.MarkupOption{ Text: text, } if v, ok := req.GetArguments()["mode"].(string); ok { opt.Mode = v } if v, ok := req.GetArguments()["context"].(string); ok { opt.Context = v } if v, ok := req.GetArguments()["filepath"].(string); ok { opt.FilePath = v } if v, ok := req.GetArguments()["wiki"].(bool); ok { opt.Wiki = v } client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } html, _, err := client.RenderMarkup(opt) if err != nil { return to.ErrorResult(fmt.Errorf("render markup err: %v", err)) } return to.TextResult(map[string]string{"html": html}) } func GetNodeInfoFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called GetNodeInfoFn") client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } info, _, err := client.GetNodeInfo() if err != nil { return to.ErrorResult(fmt.Errorf("get node info err: %v", err)) } return to.TextResult(info) } func GetSigningKeyGPGFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called GetSigningKeyGPGFn") client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } key, _, err := client.GetSigningKeyGPG() if err != nil { return to.ErrorResult(fmt.Errorf("get signing key GPG err: %v", err)) } return to.TextResult(map[string]string{"gpg_key": key}) } func GetSigningKeySSHFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { log.Debugf("Called GetSigningKeySSHFn") client, err := gitea.ClientFromContext(ctx) if err != nil { return to.ErrorResult(fmt.Errorf("get gitea client err: %v", err)) } key, _, err := client.GetSigningKeySSH() if err != nil { return to.ErrorResult(fmt.Errorf("get signing key SSH err: %v", err)) } return to.TextResult(map[string]string{"ssh_key": key}) }