forgejo-mcp/operation/operation.go
Christoph Görn 4fea365203
feat: ✨ add Actions support (dispatch_workflow, list_workflow_runs, get_workflow_run)
- Upgrade forgejo-sdk to v2.2.1-pre (post-PR #103 merge) which adds
  ActionRun, DispatchWorkflowOption, ListRepoActionRuns, etc.
- Add operation/actions package with three MCP tools:
  - dispatch_workflow: trigger a workflow run via workflow_dispatch event
  - list_workflow_runs: list runs with filtering by status/event/SHA
  - get_workflow_run: get details of a specific run by ID
- Add Actions-specific params: Workflow, Inputs, Event, RunNumber, HeadSHA, RunID, Status
- Add pkg/forgejo.GetBaseURL() helper
- Fix operation/pull/pull.go: adapt to SDK change (Body field is now *string)
- Add 11 tests with mock HTTP server

Closes #60

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-18 14:03:03 +01:00

150 lines
3.9 KiB
Go

package operation
import (
"fmt"
"codeberg.org/goern/forgejo-mcp/v2/operation/actions"
"codeberg.org/goern/forgejo-mcp/v2/operation/issue"
"codeberg.org/goern/forgejo-mcp/v2/operation/pull"
"codeberg.org/goern/forgejo-mcp/v2/operation/repo"
"codeberg.org/goern/forgejo-mcp/v2/operation/search"
"codeberg.org/goern/forgejo-mcp/v2/operation/user"
"codeberg.org/goern/forgejo-mcp/v2/operation/version"
"codeberg.org/goern/forgejo-mcp/v2/pkg/flag"
"codeberg.org/goern/forgejo-mcp/v2/pkg/forgejo"
"codeberg.org/goern/forgejo-mcp/v2/pkg/log"
"github.com/mark3labs/mcp-go/server"
)
var (
mcpServer *server.MCPServer
)
func RegisterTool(s *server.MCPServer) {
log.Info("Registering MCP tools")
RegisterUserTool(s)
RegisterRepoTool(s)
RegisterIssueTool(s)
RegisterPullTool(s)
RegisterPullReviewTool(s)
RegisterSearchTool(s)
RegisterVersionTool(s)
RegisterActionsTool(s)
log.Info("All MCP tools registered successfully")
}
// Per-domain registration functions exposed for CLI domain grouping.
func RegisterUserTool(s *server.MCPServer) {
user.RegisterTool(s)
log.Debug("Registered user tools")
}
func RegisterRepoTool(s *server.MCPServer) {
repo.RegisterTool(s)
log.Debug("Registered repository tools")
}
func RegisterIssueTool(s *server.MCPServer) {
issue.RegisterTool(s)
log.Debug("Registered issue tools")
}
func RegisterPullTool(s *server.MCPServer) {
pull.RegisterTool(s)
log.Debug("Registered pull request tools")
}
func RegisterPullReviewTool(s *server.MCPServer) {
pull.RegisterReviewTools(s)
log.Debug("Registered pull review write tools")
}
func RegisterSearchTool(s *server.MCPServer) {
search.RegisterTool(s)
log.Debug("Registered search tools")
}
func RegisterVersionTool(s *server.MCPServer) {
version.RegisterTool(s)
log.Debug("Registered version tools")
}
func RegisterActionsTool(s *server.MCPServer) {
actions.RegisterTool(s)
log.Debug("Registered actions tools")
}
func Run(transport, version string) error {
flag.Version = version
mcpServer = newMCPServer(version)
RegisterTool(mcpServer)
// Test connection to Forgejo instance before starting the server
log.Info("Testing connection to Forgejo instance",
log.SanitizedURLField("url", flag.URL),
)
if err := testConnection(); err != nil {
log.Error("Failed to connect to Forgejo instance",
log.SanitizedURLField("url", flag.URL),
log.ErrorField(err),
)
return fmt.Errorf("connection test failed: %w", err)
}
log.Info("Successfully connected to Forgejo instance",
log.SanitizedURLField("url", flag.URL),
)
switch transport {
case "stdio":
log.Info("Starting MCP server with stdio transport")
log.Info("MCP server ready for stdio communication")
if err := server.ServeStdio(mcpServer); err != nil {
log.Error("MCP stdio server failed",
log.ErrorField(err),
)
return err
}
log.Info("MCP stdio server shutdown")
case "sse":
sseServer := server.NewSSEServer(mcpServer)
log.Info("Starting MCP SSE server",
log.IntField("port", flag.SSEPort),
)
log.Info("MCP SSE server ready for connections",
log.IntField("port", flag.SSEPort),
log.StringField("endpoint", fmt.Sprintf("http://localhost:%d", flag.SSEPort)),
)
if err := sseServer.Start(fmt.Sprintf(":%d", flag.SSEPort)); err != nil {
log.Error("Failed to start SSE server",
log.IntField("port", flag.SSEPort),
log.ErrorField(err),
)
return fmt.Errorf("failed to start SSE server: %w", err)
}
log.Info("MCP SSE server shutdown")
default:
log.Error("Invalid transport configuration",
log.StringField("transport", transport),
log.StringField("valid_options", "stdio, sse"),
)
return fmt.Errorf("invalid transport type: %s. Must be 'stdio' or 'sse'", transport)
}
return nil
}
func testConnection() error {
return forgejo.VerifyConnection()
}
func newMCPServer(version string) *server.MCPServer {
return server.NewMCPServer(
"Forgejo MCP Server",
version,
server.WithLogging(),
)
}