From 8ce366a37e72e76490ad5b59fae4b76970d3e7ac Mon Sep 17 00:00:00 2001 From: Ignasi Barrera Date: Wed, 3 Dec 2025 12:40:23 +0100 Subject: [PATCH] mcp: include scopes supported in the www-authenticate header Signed-off-by: Ignasi Barrera --- .../controller/mcp_route_security_policy.go | 5 ++++ .../mcp_route_security_policy_test.go | 24 +++++++++++++++++++ tests/e2e/mcp_route_oauth_test.go | 14 +++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/internal/controller/mcp_route_security_policy.go b/internal/controller/mcp_route_security_policy.go index 1d2685c93..adf6f32b9 100644 --- a/internal/controller/mcp_route_security_policy.go +++ b/internal/controller/mcp_route_security_policy.go @@ -323,6 +323,11 @@ func buildWWWAuthenticateHeaderValue(metadata *aigv1a1.ProtectedResourceMetadata // Add resource_metadata as per RFC 9728 Section 5.1. headerValue = fmt.Sprintf(`%s, resource_metadata="%s"`, headerValue, resourceMetadataURL) + if len(metadata.ScopesSupported) > 0 { + // Add scope as per RFC 6750 Section 3. + headerValue = fmt.Sprintf(`%s, scope="%s"`, headerValue, strings.Join(metadata.ScopesSupported, " ")) + } + return headerValue } diff --git a/internal/controller/mcp_route_security_policy_test.go b/internal/controller/mcp_route_security_policy_test.go index 0f91a0ae2..902534011 100644 --- a/internal/controller/mcp_route_security_policy_test.go +++ b/internal/controller/mcp_route_security_policy_test.go @@ -654,6 +654,30 @@ func Test_buildWWWAuthenticateHeaderValue(t *testing.T) { }, expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/v1/mcp/endpoint"`, }, + { + name: "with empty scopes supported", + metadata: &aigv1a1.ProtectedResourceMetadata{ + Resource: "https://api.example.com/mcp", + ScopesSupported: []string{}, + }, + expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp"`, + }, + { + name: "with single scope supported", + metadata: &aigv1a1.ProtectedResourceMetadata{ + Resource: "https://api.example.com/mcp", + ScopesSupported: []string{"read"}, + }, + expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp", scope="read"`, + }, + { + name: "with multiple scopes supported", + metadata: &aigv1a1.ProtectedResourceMetadata{ + Resource: "https://api.example.com/mcp", + ScopesSupported: []string{"read", "write"}, + }, + expected: `Bearer error="invalid_request", error_description="No access token was provided in this request", resource_metadata="https://api.example.com/.well-known/oauth-protected-resource/mcp", scope="read write"`, + }, } for _, tt := range tests { diff --git a/tests/e2e/mcp_route_oauth_test.go b/tests/e2e/mcp_route_oauth_test.go index 40be94afd..62f5dbcc1 100644 --- a/tests/e2e/mcp_route_oauth_test.go +++ b/tests/e2e/mcp_route_oauth_test.go @@ -150,7 +150,12 @@ func TestMCPRouteOAuth(t *testing.T) { require.Contains(t, wwwAuthHeader, "Bearer", "WWW-Authenticate header should contain Bearer scheme") // Validate WWW-Authenticate header contains resource_metadata parameter. - require.Contains(t, wwwAuthHeader, "resource_metadata", "WWW-Authenticate header should contain resource_metadata parameter") + require.Contains(t, wwwAuthHeader, `resource_metadata="https://foo.bar.com/.well-known/oauth-protected-resource/mcp"`, + "WWW-Authenticate header should contain resource_metadata parameter") + t.Logf("WWW-Authenticate header: %s", wwwAuthHeader) + + // Validate WWW-Authenticate header contains scope parameter. + require.Contains(t, wwwAuthHeader, `scope="echo sum countdown"`, "WWW-Authenticate header should contain resource_metadata parameter") t.Logf("WWW-Authenticate header: %s", wwwAuthHeader) }) @@ -320,7 +325,12 @@ func TestMCPRouteOAuth(t *testing.T) { require.Contains(t, wwwAuthHeader, "Bearer", "WWW-Authenticate header should contain Bearer scheme") // Validate WWW-Authenticate header contains resource_metadata parameter. - require.Contains(t, wwwAuthHeader, "resource_metadata", "WWW-Authenticate header should contain resource_metadata parameter") + require.Contains(t, wwwAuthHeader, `resource_metadata="https://foo.bar.com/.well-known/oauth-protected-resource/mcp"`, + "WWW-Authenticate header should contain resource_metadata parameter") + t.Logf("WWW-Authenticate header: %s", wwwAuthHeader) + + // Validate WWW-Authenticate header contains scope parameter. + require.Contains(t, wwwAuthHeader, `scope="echo sum countdown"`, "WWW-Authenticate header should contain resource_metadata parameter") t.Logf("WWW-Authenticate header: %s", wwwAuthHeader) }) }