/ DEVELOPER.md
DEVELOPER.md
1 # Developer Guide 2 3 This guide covers building, developing, and contributing to the Forgejo MCP Server. 4 5 ## Prerequisites 6 7 - Go 1.24 or later 8 - make (optional, for convenience commands) 9 10 ## Building 11 12 ### Using Make 13 14 ```bash 15 make build # Build the binary (outputs ./forgejo-mcp) 16 make vendor # Tidy and verify Go module dependencies 17 ``` 18 19 ### Using Go Directly 20 21 ```bash 22 go build -v # Build the binary 23 go mod tidy # Tidy dependencies 24 ``` 25 26 ## Running Locally 27 28 ```bash 29 # stdio mode (for MCP client integration) 30 ./forgejo-mcp --transport stdio --url https://forgejo.example.org --token <token> 31 32 # SSE mode (for HTTP-based clients) 33 ./forgejo-mcp --transport sse --url https://forgejo.example.org --token <token> --sse-port 8080 34 35 # With debug logging 36 ./forgejo-mcp --transport sse --url <url> --token <token> --debug 37 ``` 38 39 Environment variables: `FORGEJO_URL`, `FORGEJO_ACCESS_TOKEN`, `FORGEJO_DEBUG`, `FORGEJO_USER_AGENT` 40 41 CLI options: `--url`, `--token`, `--transport`, `--sse-port`, `--user-agent` 42 43 ## Architecture 44 45 This is an MCP (Model Context Protocol) server that exposes Forgejo API operations as tools for AI assistants. 46 47 ### Core Flow 48 49 ``` 50 main.go → cmd/cmd.go (CLI parsing) → operation/operation.go (tool registration) → operation/{domain}/*.go (tool handlers) 51 ``` 52 53 ### Directory Structure 54 55 | Directory | Purpose | 56 |-----------|---------| 57 | `cmd/` | CLI entry point and command parsing | 58 | `operation/` | MCP tool definitions and handlers, organized by domain | 59 | `operation/issue/` | Issue-related tools | 60 | `operation/pull/` | Pull request tools | 61 | `operation/repo/` | Repository and branch tools | 62 | `operation/search/` | Search tools (users, repos, teams) | 63 | `operation/user/` | User info tools | 64 | `operation/version/` | Server version tool | 65 | `pkg/forgejo/` | Singleton Forgejo SDK client wrapper | 66 | `pkg/to/` | Response formatting helpers (`TextResult`, `ErrorResult`) | 67 | `pkg/params/` | Shared parameter descriptions for tool definitions | 68 | `pkg/flag/` | Global configuration state | 69 | `pkg/log/` | Structured logging utilities | 70 71 ## Adding a New Tool 72 73 ### Step 1: Create or Modify a Domain File 74 75 Tools are organized by domain in `operation/{domain}/`. Create a new file or add to an existing one. 76 77 ### Step 2: Define the Tool 78 79 ```go 80 package mydomain 81 82 import ( 83 "context" 84 "fmt" 85 86 "codeberg.org/goern/forgejo-mcp/v2/pkg/forgejo" 87 "codeberg.org/goern/forgejo-mcp/v2/pkg/params" 88 "codeberg.org/goern/forgejo-mcp/v2/pkg/to" 89 "github.com/mark3labs/mcp-go/mcp" 90 "github.com/mark3labs/mcp-go/server" 91 ) 92 93 // Tool definition 94 var MyTool = mcp.NewTool( 95 "my_tool_name", 96 mcp.WithDescription("What this tool does"), 97 mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)), 98 mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)), 99 mcp.WithNumber("limit", mcp.Description("Page size"), mcp.DefaultNumber(20)), 100 ) 101 102 // Handler function 103 func MyToolFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { 104 // Extract parameters (numbers come as float64) 105 owner, _ := req.Params.Arguments["owner"].(string) 106 repo, _ := req.Params.Arguments["repo"].(string) 107 limit, _ := req.Params.Arguments["limit"].(float64) 108 109 // Call Forgejo API 110 result, _, err := forgejo.Client().SomeMethod(owner, repo, int(limit)) 111 if err != nil { 112 return to.ErrorResult(fmt.Errorf("operation failed: %v", err)) 113 } 114 115 // Return formatted result 116 return to.TextResult(result) 117 } 118 ``` 119 120 ### Step 3: Register the Tool 121 122 Add registration in the domain's file: 123 124 ```go 125 func RegisterTool(s *server.MCPServer) { 126 s.AddTool(MyTool, MyToolFn) 127 } 128 ``` 129 130 ### Step 4: Wire Up New Domains 131 132 If you created a new domain, import and register it in `operation/operation.go`: 133 134 ```go 135 import "codeberg.org/goern/forgejo-mcp/v2/operation/mydomain" 136 137 func RegisterTools(s *server.MCPServer) { 138 // ... existing registrations 139 mydomain.RegisterTool(s) 140 } 141 ``` 142 143 ## Key Patterns 144 145 ### Parameter Handling 146 147 - String parameters: `value, _ := req.Params.Arguments["param"].(string)` 148 - Number parameters: `value, _ := req.Params.Arguments["num"].(float64)` (always float64) 149 - Optional with defaults: Check if value exists before using 150 151 ### Response Formatting 152 153 Use helpers from `pkg/to/`: 154 155 ```go 156 // Success response 157 return to.TextResult(data) 158 159 // Error response 160 return to.ErrorResult(fmt.Errorf("something went wrong: %v", err)) 161 ``` 162 163 ### Shared Parameter Descriptions 164 165 Reuse descriptions from `pkg/params/` for consistency: 166 167 ```go 168 mcp.WithString("owner", mcp.Required(), mcp.Description(params.Owner)) 169 mcp.WithString("repo", mcp.Required(), mcp.Description(params.Repo)) 170 mcp.WithNumber("page", mcp.Description(params.Page), mcp.DefaultNumber(1)) 171 ``` 172 173 ## Dependencies 174 175 | Package | Purpose | 176 |---------|---------| 177 | `codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v2` | Forgejo API client | 178 | `github.com/mark3labs/mcp-go` | MCP protocol implementation | 179 | `github.com/spf13/cobra` | CLI framework | 180 181 ## Testing 182 183 Run with debug mode to troubleshoot issues: 184 185 ```bash 186 FORGEJO_DEBUG=true ./forgejo-mcp --transport stdio --url <url> --token <token> 187 ``` 188 189 ## Blocked Features 190 191 Some planned features are blocked on upstream API or SDK support: 192 193 | Feature | Status | Details | 194 |---------|--------|---------| 195 | Wiki support | Blocked | Waiting for forgejo-sdk wiki API | 196 | Projects/Kanban | Blocked | Requires Gitea 1.26.0 API | 197 198 See `docs/plans/` for detailed status: 199 - `wiki-support.md` - Wiki API implementation plan 200 - `projects-support.md` - Projects/Kanban implementation plan 201 202 ## Contributing 203 204 1. Fork the repository on Codeberg 205 2. Create a feature branch 206 3. Make your changes following the patterns above 207 4. Test locally with both stdio and SSE modes 208 5. Submit a pull request 209 210 ### Code Style 211 212 - Follow standard Go conventions 213 - Use meaningful variable names 214 - Add tool descriptions that clearly explain what each tool does 215 - Reuse parameter descriptions from `pkg/params/` where applicable