mcp: scaffolding of /.pomerium/mcp routes (#5580)

This commit is contained in:
Denis Mishin 2025-04-23 12:36:31 -04:00 committed by GitHub
parent cb0e8aaf06
commit f1a9401ddc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 100 additions and 0 deletions

View file

@ -1,5 +1,18 @@
package mcp
import (
"context"
"net/http"
"path"
"github.com/gorilla/mux"
"github.com/rs/cors"
oteltrace "go.opentelemetry.io/otel/trace"
"github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/pkg/telemetry/trace"
)
const (
DefaultPrefix = "/.pomerium/mcp"
@ -9,3 +22,39 @@ const (
revocationEndpoint = "/revoke"
tokenEndpoint = "/token"
)
type Handler struct {
prefix string
trace oteltrace.TracerProvider
}
func New(
ctx context.Context,
prefix string,
_ *config.Config,
) (*Handler, error) {
tracerProvider := trace.NewTracerProvider(ctx, "MCP")
return &Handler{
prefix: prefix,
trace: tracerProvider,
}, nil
}
// HandlerFunc returns a http.HandlerFunc that handles the mcp endpoints.
func (srv *Handler) HandlerFunc() http.HandlerFunc {
r := mux.NewRouter()
r.Use(cors.New(cors.Options{
AllowedMethods: []string{http.MethodGet, http.MethodPost, http.MethodOptions},
AllowedOrigins: []string{"*"},
AllowedHeaders: []string{"content-type", "mcp-protocol-version"},
}).Handler)
r.Methods(http.MethodOptions).HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
r.Path(path.Join(srv.prefix, registerEndpoint)).Methods(http.MethodPost).HandlerFunc(srv.RegisterClient)
r.Path(path.Join(srv.prefix, authorizationEndpoint)).Methods(http.MethodGet).HandlerFunc(srv.Authorize)
r.Path(path.Join(srv.prefix, oauthCallbackEndpoint)).Methods(http.MethodGet).HandlerFunc(srv.OAuthCallback)
r.Path(path.Join(srv.prefix, tokenEndpoint)).Methods(http.MethodPost).HandlerFunc(srv.Token)
return r.ServeHTTP
}

View file

@ -0,0 +1,10 @@
package mcp
import (
"net/http"
)
// Authorize handles the /authorize endpoint.
func (srv *Handler) Authorize(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}

View file

@ -0,0 +1,9 @@
package mcp
import (
"net/http"
)
func (srv *Handler) OAuthCallback(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}

View file

@ -0,0 +1,11 @@
package mcp
import (
"net/http"
)
// RegisterClient handles the /register endpoint.
// It is used to register a new client with the MCP server.
func (srv *Handler) RegisterClient(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}

View file

@ -0,0 +1,10 @@
package mcp
import (
"net/http"
)
// Token handles the /token endpoint.
func (srv *Handler) Token(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}

View file

@ -24,6 +24,9 @@ func (p *Proxy) registerDashboardHandlers(r *mux.Router, opts *config.Options) *
h := httputil.DashboardSubrouter(r)
h.Use(middleware.SetHeaders(httputil.HeadersContentSecurityPolicy))
// model context protocol
h.PathPrefix("/mcp").Handler(p.mcp.HandlerFunc())
// special pomerium endpoints for users to view their session
h.Path("/").Handler(httputil.HandlerFunc(p.userInfo)).Methods(http.MethodGet)
h.Path("/device-enrolled").Handler(httputil.HandlerFunc(p.deviceEnrolled))

View file

@ -18,6 +18,7 @@ import (
"github.com/pomerium/pomerium/internal/handlers/webauthn"
"github.com/pomerium/pomerium/internal/httputil"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/mcp"
"github.com/pomerium/pomerium/internal/telemetry/metrics"
"github.com/pomerium/pomerium/pkg/cryptutil"
"github.com/pomerium/pomerium/pkg/storage"
@ -63,6 +64,7 @@ type Proxy struct {
webauthn *webauthn.Handler
tracerProvider oteltrace.TracerProvider
logoProvider portal.LogoProvider
mcp *mcp.Handler
}
// New takes a Proxy service from options and a validation function.
@ -74,12 +76,18 @@ func New(ctx context.Context, cfg *config.Config) (*Proxy, error) {
return nil, err
}
mcp, err := mcp.New(ctx, mcp.DefaultPrefix, cfg)
if err != nil {
return nil, fmt.Errorf("proxy: failed to create mcp handler: %w", err)
}
p := &Proxy{
tracerProvider: tracerProvider,
state: atomicutil.NewValue(state),
currentConfig: atomicutil.NewValue(&config.Config{Options: config.NewDefaultOptions()}),
currentRouter: atomicutil.NewValue(httputil.NewRouter()),
logoProvider: portal.NewLogoProvider(),
mcp: mcp,
}
p.OnConfigChange(ctx, cfg)
p.webauthn = webauthn.New(p.getWebauthnState)