/ 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