Skip to content

Commit da6f9bc

Browse files
Merge remote-tracking branch 'origin/main' into merge-main-into-release-0.7.0
2 parents a260959 + 8139fc6 commit da6f9bc

9 files changed

Lines changed: 432 additions & 395 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ COPY internal/ internal/
1111
COPY api/ api/
1212

1313
ARG LDFLAGS=""
14-
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags "${LDFLAGS}" -o mcp_gateway cmd/mcp-broker-router/main.go
14+
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags "${LDFLAGS}" -o mcp_gateway ./cmd/mcp-broker-router/
1515

1616
FROM alpine:3.22.1
1717

cmd/mcp-broker-router/broker.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"os"
7+
"time"
8+
9+
mcpv1alpha1 "github.com/Kuadrant/mcp-gateway/api/v1alpha1"
10+
"github.com/Kuadrant/mcp-gateway/internal/broker"
11+
"github.com/mark3labs/mcp-go/server"
12+
"go.opentelemetry.io/otel"
13+
"go.opentelemetry.io/otel/propagation"
14+
)
15+
16+
func (a *app) createBroker() {
17+
invalidToolPolicy := mcpv1alpha1.InvalidToolPolicy(a.brokerCfg.invalidToolPolicy)
18+
if invalidToolPolicy != mcpv1alpha1.InvalidToolPolicyFilterOut && invalidToolPolicy != mcpv1alpha1.InvalidToolPolicyRejectServer {
19+
panic("--invalid-tool-policy must be FilterOut or RejectServer")
20+
}
21+
22+
managerTickerInterval := time.Duration(a.brokerCfg.managerTickerIntervalSecs) * time.Second
23+
if managerTickerInterval <= 0 {
24+
panic("flag mcp-check-interval cannot be 0 or less seconds")
25+
}
26+
27+
a.mcpBroker = broker.NewBroker(a.logger.With("component", "broker"),
28+
broker.WithEnforceCapabilityFilter(a.brokerCfg.enforceCapabilityFiltering),
29+
broker.WithTrustedHeadersPublicKey(os.Getenv("TRUSTED_HEADER_PUBLIC_KEY")),
30+
broker.WithManagerTickerInterval(managerTickerInterval),
31+
broker.WithInvalidToolPolicy(invalidToolPolicy),
32+
broker.WithElicitationEnabled(a.brokerCfg.enableURLElicitation),
33+
broker.WithDiscoveryToolsEnabled(a.brokerCfg.discoveryToolsEnabled),
34+
broker.WithDiscoveryToolThreshold(a.brokerCfg.discoveryToolThreshold),
35+
broker.WithSessionCache(a.sessionCache),
36+
)
37+
a.tokenHandler = broker.NewTokenHandler(a.sessionCache, a.tokenElicitMap, *a.logger)
38+
a.elicitHandler = &broker.ElicitationHandler{
39+
ElicitationMap: a.tokenElicitMap,
40+
Config: a.mcpConfig,
41+
}
42+
a.setUpHTTPServer()
43+
}
44+
45+
func (a *app) setUpHTTPServer() {
46+
cfg := &a.brokerCfg
47+
mux := http.NewServeMux()
48+
49+
mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
50+
_, _ = fmt.Fprint(w, "Hello, World! BTW, the MCP server is on /mcp")
51+
})
52+
53+
mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
54+
w.WriteHeader(http.StatusOK)
55+
})
56+
57+
mux.HandleFunc("/readyz", func(w http.ResponseWriter, _ *http.Request) {
58+
if !a.mcpBroker.IsReady() {
59+
w.WriteHeader(http.StatusServiceUnavailable)
60+
return
61+
}
62+
w.WriteHeader(http.StatusOK)
63+
})
64+
65+
oauthHandler := broker.ProtectedResourceHandler{Logger: a.logger}
66+
mux.HandleFunc("/.well-known/oauth-protected-resource", oauthHandler.Handle)
67+
mux.HandleFunc("/.well-known/oauth-protected-resource/", oauthHandler.Handle)
68+
69+
// WriteTimeout of 0 (disabled) is important for SSE connections (GET /mcp).
70+
// SSE streams notifications indefinitely - any write timeout would kill the connection.
71+
writeTimeout := time.Duration(cfg.writeTimeoutSecs) * time.Second
72+
73+
httpSrv := &http.Server{
74+
Addr: cfg.addr,
75+
Handler: mux,
76+
ReadTimeout: 5 * time.Second,
77+
WriteTimeout: writeTimeout,
78+
}
79+
80+
streamableHTTPOpts := []server.StreamableHTTPOption{
81+
server.WithStreamableHTTPServer(httpSrv),
82+
}
83+
if a.jwtMgr != nil {
84+
streamableHTTPOpts = append(streamableHTTPOpts, server.WithSessionIdManager(a.jwtMgr))
85+
}
86+
streamableHTTPServer := server.NewStreamableHTTPServer(a.mcpBroker.MCPServer(), streamableHTTPOpts...)
87+
88+
mux.HandleFunc("OPTIONS /mcp", func(w http.ResponseWriter, r *http.Request) {
89+
a.logger.Debug("Handling OPTIONS", "Mcp-Session-Id", r.Header.Get("Mcp-Session-Id"))
90+
w.WriteHeader(http.StatusOK)
91+
})
92+
93+
mux.HandleFunc("/status", a.mcpBroker.HandleStatusRequest)
94+
mux.HandleFunc("/status/", a.mcpBroker.HandleStatusRequest)
95+
if cfg.enableURLElicitation {
96+
mux.Handle("/tokens", a.tokenHandler)
97+
mux.Handle("/mcp/elicitation", a.elicitHandler)
98+
}
99+
mux.Handle("/mcp", traceContextMiddleware(streamableHTTPServer))
100+
101+
a.brokerServer = httpSrv
102+
a.mcpServer = streamableHTTPServer
103+
}
104+
105+
func traceContextMiddleware(next http.Handler) http.Handler {
106+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
107+
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
108+
next.ServeHTTP(w, r.WithContext(ctx))
109+
})
110+
}

0 commit comments

Comments
 (0)