Skip to content

Commit 91eb4f9

Browse files
authored
Add RFC-9728 discovery endpoint (#1287)
1 parent ae59712 commit 91eb4f9

File tree

23 files changed

+370
-32
lines changed

23 files changed

+370
-32
lines changed

cmd/thv-operator/controllers/mcpserver_controller.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func (r *MCPServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
213213

214214
// Update the MCPServer status with the service URL
215215
if mcpServer.Status.URL == "" {
216-
mcpServer.Status.URL = fmt.Sprintf("http://%s.%s.svc.cluster.local:%d", service.Name, service.Namespace, mcpServer.Spec.Port)
216+
mcpServer.Status.URL = createServiceURL(mcpServer.Name, mcpServer.Namespace, mcpServer.Spec.Port)
217217
err = r.Status().Update(ctx, mcpServer)
218218
if err != nil {
219219
ctxLogger.Error(err, "Failed to update MCPServer status")
@@ -428,6 +428,10 @@ func (r *MCPServerReconciler) deploymentForMCPServer(m *mcpv1alpha1.MCPServer) *
428428

429429
oidcArgs := r.generateOIDCArgs(ctx, m)
430430
args = append(args, oidcArgs...)
431+
432+
// Add OAuth discovery resource URL for RFC 9728 compliance
433+
resourceURL := createServiceURL(m.Name, m.Namespace, m.Spec.Port)
434+
args = append(args, fmt.Sprintf("--resource-url=%s", resourceURL))
431435
}
432436

433437
// Add authorization configuration args
@@ -625,6 +629,12 @@ func createServiceName(mcpServerName string) string {
625629
return fmt.Sprintf("mcp-%s-proxy", mcpServerName)
626630
}
627631

632+
// createServiceURL generates the full cluster-local service URL for an MCP server
633+
func createServiceURL(mcpServerName, namespace string, port int32) string {
634+
serviceName := createServiceName(mcpServerName)
635+
return fmt.Sprintf("http://%s.%s.svc.cluster.local:%d", serviceName, namespace, port)
636+
}
637+
628638
// serviceForMCPServer returns a MCPServer Service object
629639
func (r *MCPServerReconciler) serviceForMCPServer(m *mcpv1alpha1.MCPServer) *corev1.Service {
630640
ls := labelsForMCPServer(m.Name)

cmd/thv-proxyrunner/app/run.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ var (
7878

7979
// Tools filter
8080
runToolsFilter []string
81+
82+
// OAuth discovery resource URL
83+
runResourceURL string
8184
)
8285

8386
func init() {
@@ -185,6 +188,12 @@ func init() {
185188
nil,
186189
"Filter MCP server tools (comma-separated list of tool names)",
187190
)
191+
runCmd.Flags().StringVar(
192+
&runResourceURL,
193+
"resource-url",
194+
"",
195+
"Explicit resource URL for OAuth discovery endpoint (RFC 9728)",
196+
)
188197
}
189198

190199
func runCmdFunc(cmd *cobra.Command, args []string) error {
@@ -248,7 +257,7 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
248257
WithTransportAndPorts(runTransport, runProxyPort, runTargetPort).
249258
WithAuditEnabled(runEnableAudit, runAuditConfig).
250259
WithOIDCConfig(oidcIssuer, oidcAudience, oidcJwksURL, oidcIntrospectionURL, oidcClientID, oidcClientSecret,
251-
runThvCABundle, runJWKSAuthTokenFile, runJWKSAllowPrivateIP).
260+
runThvCABundle, runJWKSAuthTokenFile, runResourceURL, runJWKSAllowPrivateIP).
252261
WithTelemetryConfig(finalOtelEndpoint, runOtelEnablePrometheusMetricsPath, runOtelServiceName,
253262
finalOtelSamplingRate, runOtelHeaders, runOtelInsecure, finalOtelEnvironmentVariables).
254263
WithToolsFilter(runToolsFilter).

cmd/thv/app/proxy.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ var (
8686
proxyPort int
8787
proxyTargetURI string
8888

89+
resourceURL string // Explicit resource URL for OAuth discovery endpoint (RFC 9728)
90+
8991
// Remote server authentication flags
9092
remoteAuthIssuer string
9193
remoteAuthClientID string
@@ -126,6 +128,9 @@ func init() {
126128
// Add OIDC validation flags
127129
AddOIDCFlags(proxyCmd)
128130

131+
proxyCmd.Flags().StringVar(&resourceURL, "resource-url", "",
132+
"Explicit resource URL for OAuth discovery endpoint (RFC 9728)")
133+
129134
// Add remote server authentication flags
130135
proxyCmd.Flags().BoolVar(&enableRemoteAuth, "remote-auth", false, "Enable OAuth authentication to remote MCP server")
131136
proxyCmd.Flags().StringVar(&remoteAuthIssuer, "remote-auth-issuer", "",
@@ -215,11 +220,12 @@ func proxyCmdFunc(cmd *cobra.Command, args []string) error {
215220
IntrospectionURL: introspectionURL,
216221
ClientID: clientID,
217222
ClientSecret: clientSecret,
223+
ResourceURL: resourceURL,
218224
}
219225
}
220226

221227
// Get authentication middleware for incoming requests
222-
authMiddleware, err := auth.GetAuthenticationMiddleware(ctx, oidcConfig)
228+
authMiddleware, authInfoHandler, err := auth.GetAuthenticationMiddleware(ctx, oidcConfig)
223229
if err != nil {
224230
return fmt.Errorf("failed to create authentication middleware: %v", err)
225231
}
@@ -236,7 +242,11 @@ func proxyCmdFunc(cmd *cobra.Command, args []string) error {
236242
port, proxyTargetURI)
237243

238244
// Create the transparent proxy with middlewares
239-
proxy := transparent.NewTransparentProxy(proxyHost, port, serverName, proxyTargetURI, nil, false, middlewares...)
245+
proxy := transparent.NewTransparentProxy(
246+
proxyHost, port, serverName, proxyTargetURI,
247+
nil, authInfoHandler,
248+
false,
249+
middlewares...)
240250
if err := proxy.Start(ctx); err != nil {
241251
return fmt.Errorf("failed to start proxy: %v", err)
242252
}

cmd/thv/app/run_flags.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ type RunFlags struct {
5252
JWKSAuthTokenFile string
5353
JWKSAllowPrivateIP bool
5454

55+
// OAuth discovery configuration
56+
ResourceURL string
57+
5558
// Telemetry configuration
5659
OtelEndpoint string
5760
OtelServiceName string
@@ -140,6 +143,10 @@ func AddRunFlags(cmd *cobra.Command, config *RunFlags) {
140143
cmd.Flags().BoolVar(&config.JWKSAllowPrivateIP, "jwks-allow-private-ip", false,
141144
"Allow JWKS/OIDC endpoints on private IP addresses (use with caution)")
142145

146+
// OAuth discovery configuration
147+
cmd.Flags().StringVar(&config.ResourceURL, "resource-url", "",
148+
"Explicit resource URL for OAuth discovery endpoint (RFC 9728)")
149+
143150
// OpenTelemetry flags updated per origin/main
144151
cmd.Flags().StringVar(&config.OtelEndpoint, "otel-endpoint", "",
145152
"OpenTelemetry OTLP endpoint URL (e.g., https://api.honeycomb.io)")
@@ -271,7 +278,7 @@ func BuildRunnerConfig(
271278
WithLabels(runConfig.Labels).
272279
WithGroup(runConfig.Group).
273280
WithOIDCConfig(oidcIssuer, oidcAudience, oidcJwksURL, oidcIntrospectionURL, oidcClientID, oidcClientSecret,
274-
runConfig.ThvCABundle, runConfig.JWKSAuthTokenFile, runConfig.JWKSAllowPrivateIP).
281+
runConfig.ThvCABundle, runConfig.JWKSAuthTokenFile, runConfig.ResourceURL, runConfig.JWKSAllowPrivateIP).
275282
WithTelemetryConfig(finalOtelEndpoint, runConfig.OtelEnablePrometheusMetricsPath, runConfig.OtelServiceName,
276283
finalOtelSamplingRate, runConfig.OtelHeaders, runConfig.OtelInsecure, finalOtelEnvironmentVariables).
277284
WithToolsFilter(runConfig.ToolsFilter).

docs/cli/thv_proxy.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/cli/thv_run.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/server/docs.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/server/swagger.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/server/swagger.yaml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/api/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func Serve(
155155
r.Use(updateCheckMiddleware())
156156

157157
// Add authentication middleware
158-
authMiddleware, err := auth.GetAuthenticationMiddleware(ctx, oidcConfig)
158+
authMiddleware, _, err := auth.GetAuthenticationMiddleware(ctx, oidcConfig)
159159
if err != nil {
160160
return fmt.Errorf("failed to create authentication middleware: %v", err)
161161
}

0 commit comments

Comments
 (0)