package main import ( "context" "log/slog" "net/http" "os" "strings" chassisauth "git.d-ma.be/mathias/mcp-chassis/auth" "git.d-ma.be/mathias/gitea-mcp/internal/allowlist" "git.d-ma.be/mathias/gitea-mcp/internal/auth" "git.d-ma.be/mathias/gitea-mcp/internal/config" "git.d-ma.be/mathias/gitea-mcp/internal/gitea" "git.d-ma.be/mathias/gitea-mcp/internal/mcp" "git.d-ma.be/mathias/gitea-mcp/internal/registry" "git.d-ma.be/mathias/gitea-mcp/internal/tools" ) // version is the build version, overridable via -ldflags "-X main.version=". // Defaults to "dev" for local / un-stamped builds (was a hardcoded, drifting // "0.1.0" — it now tells the truth instead of a stale literal). var version = "dev" func main() { logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) // Route the chassis's package-level slog (auth audit logs, gitea-mcp#9) through // the same structured handler as the rest of the server. slog.SetDefault(logger) cfg, err := config.Load() if err != nil { logger.Error("load config", "err", err) os.Exit(1) } ctx := context.Background() jwtValidator, jwtInitErr := chassisauth.NewJWTValidator(ctx, cfg.DexIssuerURL, cfg.MCPAudience) if jwtInitErr != nil { logger.Warn("jwt validator init failed; JWT auth degraded", "err", jwtInitErr) } giteaClient := gitea.NewClient(cfg.GiteaBaseURL, cfg.DefaultToken) ownerAllow := allowlist.New(cfg.AllowedOwners) reg := registry.New() tools.RegisterAll(reg, giteaClient, ownerAllow, cfg.GiteaBaseURL, "mathias", "template-go-web") mcpSrv := mcp.NewServer(mcp.ServerOptions{ Registry: reg, Sessions: mcp.NewSessionStore(), }) // resourceMetadataURL is only emitted in the WWW-Authenticate challenge // when both MCPResourceURL and a Dex issuer are wired; empty disables // the challenge so static-only clients aren't pushed into OAuth discovery. var resourceMetadataURL string if cfg.MCPResourceURL != "" && cfg.DexIssuerURL != "" { resourceMetadataURL = strings.TrimRight(cfg.MCPResourceURL, "/") + "/.well-known/oauth-protected-resource" } mux := http.NewServeMux() mux.Handle("/mcp", mcp.OriginAllowlist(cfg.OriginAllowlist)( chassisauth.BearerMiddleware(cfg.StaticToken, jwtValidator, "gitea", resourceMetadataURL, auth.CallerMiddleware(logger, mcpSrv), ), )) mux.Handle("/healthz", newHealthzHandler(cfg.DexIssuerURL != "", jwtValidator != nil, jwtInitErr)) if cfg.DexIssuerURL != "" { mux.HandleFunc("GET /.well-known/oauth-protected-resource", chassisauth.ProtectedResourceHandler(cfg.MCPResourceURL, cfg.DexIssuerURL)) } addr := ":" + cfg.Port logger.Info("gitea-mcp starting", "addr", addr, "version", version) if err := http.ListenAndServe(addr, mux); err != nil { logger.Error("server stopped", "err", err) os.Exit(1) } }