forgejo-mcp/operation/org/membership.go
Christoph Görn dd9116fbca
fix: 🚨 clear golangci-lint v2 backlog (closes bead forgejo-mcp-hc9)
- errorlint: fmt.Errorf %v→%w across all handlers (errors now wrap the
  underlying SDK/HTTP error for errors.Is/As); errors.Is for
  context.Canceled in cmd
- staticcheck quickfixes: Fprintf over WriteString(Sprintf), tagged
  switches, omit inferred 'any'; QF1001 resolved by hoisting hex checks
  into isHex predicates (normalizeColor, validateSHA)
- govet: reflect.Ptr → reflect.Pointer in pkg/ptr
- errcheck: explicit '_ =' for fs.Parse (ExitOnError) and deferred
  zap Sync
- repair four test assertions the autofix broke (it dropped the
  're.Code != X' half of combined type-assert checks, inverting the
  test); all errors.As sites use 'var re *resource.ResourceError'

golangci-lint: 0 issues. staticcheck, vet, tests: clean.
2026-06-11 00:03:36 +02:00

125 lines
3.7 KiB
Go

package org
import (
"context"
"errors"
"fmt"
"codeberg.org/goern/forgejo-mcp/v2/operation/params"
"codeberg.org/goern/forgejo-mcp/v2/pkg/forgejo"
"codeberg.org/goern/forgejo-mcp/v2/pkg/log"
"codeberg.org/goern/forgejo-mcp/v2/pkg/to"
forgejo_sdk "codeberg.org/mvdkleijn/forgejo-sdk/forgejo/v3"
"github.com/mark3labs/mcp-go/mcp"
)
const (
ListOrgMembersToolName = "list_org_members"
CheckOrgMembershipToolName = "check_org_membership"
RemoveOrgMemberToolName = "remove_org_member"
)
var (
ListOrgMembersTool = mcp.NewTool(
ListOrgMembersToolName,
mcp.WithDescription("List members of an organization"),
mcp.WithString("org", mcp.Required(), mcp.Description(params.Org)),
mcp.WithNumber("page", mcp.Required(), mcp.Description(params.Page), mcp.DefaultNumber(1), mcp.Min(1)),
mcp.WithNumber("limit", mcp.Required(), mcp.Description(params.Limit), mcp.DefaultNumber(100), mcp.Min(1)),
)
CheckOrgMembershipTool = mcp.NewTool(
CheckOrgMembershipToolName,
mcp.WithDescription("Check if a user is a member of an organization"),
mcp.WithString("org", mcp.Required(), mcp.Description(params.Org)),
mcp.WithString("user", mcp.Required(), mcp.Description(params.User)),
)
RemoveOrgMemberTool = mcp.NewTool(
RemoveOrgMemberToolName,
mcp.WithDescription("Remove a member from an organization"),
mcp.WithString("org", mcp.Required(), mcp.Description(params.Org)),
mcp.WithString("user", mcp.Required(), mcp.Description(params.User)),
)
)
func ListOrgMembersFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called ListOrgMembersFn")
orgName, ok := req.GetArguments()["org"].(string)
if !ok {
return to.ErrorResult(errors.New("organization name is required"))
}
page, ok := req.GetArguments()["page"].(float64)
if !ok {
page = 1
}
limit, ok := req.GetArguments()["limit"].(float64)
if !ok {
limit = 100
}
opt := forgejo_sdk.ListOrgMembershipOption{
ListOptions: forgejo_sdk.ListOptions{
Page: int(page),
PageSize: int(limit),
},
}
client, err := forgejo.Client(ctx)
if err != nil {
return to.ErrorResult(err)
}
members, _, err := client.ListOrgMembership(orgName, opt)
if err != nil {
return to.ErrorResult(fmt.Errorf("list org members err: %w", err))
}
return to.TextResult(members)
}
func CheckOrgMembershipFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called CheckOrgMembershipFn")
orgName, ok := req.GetArguments()["org"].(string)
if !ok {
return to.ErrorResult(errors.New("organization name is required"))
}
user, ok := req.GetArguments()["user"].(string)
if !ok {
return to.ErrorResult(errors.New("username is required"))
}
client, err := forgejo.Client(ctx)
if err != nil {
return to.ErrorResult(err)
}
isMember, _, err := client.CheckOrgMembership(orgName, user)
if err != nil {
return to.ErrorResult(fmt.Errorf("check org membership err: %w", err))
}
return to.TextResult(map[string]interface{}{
"org": orgName,
"user": user,
"is_member": isMember,
})
}
func RemoveOrgMemberFn(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
log.Debugf("Called RemoveOrgMemberFn")
orgName, ok := req.GetArguments()["org"].(string)
if !ok {
return to.ErrorResult(errors.New("organization name is required"))
}
user, ok := req.GetArguments()["user"].(string)
if !ok {
return to.ErrorResult(errors.New("username is required"))
}
client, err := forgejo.Client(ctx)
if err != nil {
return to.ErrorResult(err)
}
_, err = client.DeleteOrgMembership(orgName, user)
if err != nil {
return to.ErrorResult(fmt.Errorf("remove org member err: %w", err))
}
return to.TextResult(fmt.Sprintf("User '%s' removed from organization '%s'", user, orgName))
}