feat(ingestion): migrate to gitea.d-ma.be/mathias/mcp-chassis v0.1.0
Second port of the MCP chassis (gitea-mcp was first, commit 658f4ba). Closes the chassis-adoption loop on the two highest-LOC consumers. Changes: - Drop ingestion/internal/auth/ entirely (jwt.go + jwt_test.go + protected_resource.go + protected_resource_test.go) — chassis provides JWTValidator + ProtectedResourceHandler with identical semantics. - Drop ingestion/internal/mcp/auth.go (BearerAuth function, ~65 LOC) and the integration test auth_test.go (~200 LOC) — chassis BearerMiddleware replaces it. Static-Bearer-or-Dex-JWT precedence and RFC 9728 resource_metadata challenge behavior preserved 1:1. - cmd/server/main.go: import chassis as `chassisauth`, rewire the three call sites. Use realm="brain" in the BearerMiddleware call so a 401 challenge identifies the resource as the brain MCP. OAuth client_credentials handler (ingestion/internal/oauth) stays — chassis v0.1.0 covers only the JWT path; OAuth flow is a candidate for chassis v0.2.0 once a second MCP needs it (rule of three). Net delta: -~330 LOC of duplicated auth code; +1 import; +1 GOPRIVATE env requirement on dev machines (documented in the spike handoff 2026-05-22-mcp-chassis-spike.md). task check green (lint + test + vet + govulncheck). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,8 +12,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
chassisauth "gitea.d-ma.be/mathias/mcp-chassis/auth"
|
||||
|
||||
"github.com/mathiasbq/hyperguild/ingestion/internal/api"
|
||||
"github.com/mathiasbq/hyperguild/ingestion/internal/auth"
|
||||
"github.com/mathiasbq/hyperguild/ingestion/internal/llm"
|
||||
"github.com/mathiasbq/hyperguild/ingestion/internal/mcp"
|
||||
"github.com/mathiasbq/hyperguild/ingestion/internal/embed"
|
||||
@@ -181,16 +182,13 @@ func main() {
|
||||
mux.HandleFunc("POST /backfill-refs", h.BackfillRefs)
|
||||
mux.HandleFunc("POST /backfill-embeddings", h.BackfillEmbeddings)
|
||||
mux.HandleFunc("GET /pass-rate", h.PassRate)
|
||||
var jwtValidator *auth.Validator
|
||||
if dexURL := os.Getenv("DEX_ISSUER_URL"); dexURL != "" {
|
||||
audience := os.Getenv("MCP_AUDIENCE")
|
||||
v, err := auth.NewValidator(dexURL, audience)
|
||||
if err != nil {
|
||||
logger.Error("build jwt validator", "err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
jwtValidator = v
|
||||
logger.Info("jwt auth enabled", "issuer", dexURL)
|
||||
jwtValidator, err := chassisauth.NewJWTValidator(ctx, os.Getenv("DEX_ISSUER_URL"), os.Getenv("MCP_AUDIENCE"))
|
||||
if err != nil {
|
||||
logger.Error("build jwt validator", "err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if jwtValidator != nil {
|
||||
logger.Info("jwt auth enabled", "issuer", os.Getenv("DEX_ISSUER_URL"))
|
||||
}
|
||||
|
||||
// Resource-metadata URL is only emitted on 401 when Dex OAuth is
|
||||
@@ -200,13 +198,13 @@ func main() {
|
||||
if dexURL := os.Getenv("DEX_ISSUER_URL"); dexURL != "" {
|
||||
resourceURL := os.Getenv("MCP_RESOURCE_URL")
|
||||
mux.HandleFunc("GET /.well-known/oauth-protected-resource",
|
||||
auth.ProtectedResourceHandler(resourceURL, dexURL))
|
||||
chassisauth.ProtectedResourceHandler(resourceURL, dexURL))
|
||||
if resourceURL != "" {
|
||||
resourceMetadataURL = strings.TrimRight(resourceURL, "/") + "/.well-known/oauth-protected-resource"
|
||||
}
|
||||
}
|
||||
|
||||
mux.Handle("/mcp", mcp.BearerAuth(mcpToken, jwtValidator, resourceMetadataURL, mcpSrv))
|
||||
mux.Handle("/mcp", chassisauth.BearerMiddleware(mcpToken, jwtValidator, "brain", resourceMetadataURL, mcpSrv))
|
||||
|
||||
// Opt-in OAuth 2.0 client_credentials flow for claude.ai's custom-MCP
|
||||
// integration UI, which has no static-Bearer field. Setting both
|
||||
|
||||
Reference in New Issue
Block a user