Skip to content

Commit f7e69fc

Browse files
yroblataskbotjhrozek
authored
Fix VirtualMCPServer reconciliation for discovered auth config updates (#2957)
* Fix VirtualMCPServer reconciliation for discovered auth config updates When an MCPExternalAuthConfig is updated, VirtualMCPServer resources should reconcile to pick up the changes. However, the watch handler only checked inline references in the VirtualMCPServer.Spec.OutgoingAuth field and ignored discovered references when source: discovered mode is used. In discovered mode, auth configs are referenced through MCPServer resources in the group rather than inline in the VirtualMCPServer spec. The watch handler now checks both inline and discovered references by listing MCPServers in the group and checking if any reference the updated MCPExternalAuthConfig. This ensures that VirtualMCPServers using discovered mode will properly reconcile when their backend auth configurations change. Fixes #2831 * changes from review --------- Co-authored-by: taskbot <[email protected]> Co-authored-by: Jakub Hrozek <[email protected]>
1 parent 71de38f commit f7e69fc

File tree

3 files changed

+557
-6
lines changed

3 files changed

+557
-6
lines changed

cmd/thv-operator/controllers/virtualmcpserver_controller.go

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,7 +1717,8 @@ func (r *VirtualMCPServerReconciler) mapExternalAuthConfigToVirtualMCPServer(
17171717
var requests []reconcile.Request
17181718
for _, vmcp := range vmcpList.Items {
17191719
// Only reconcile VirtualMCPServers that actually reference this ExternalAuthConfig
1720-
if r.vmcpReferencesExternalAuthConfig(&vmcp, externalAuthConfig.Name) {
1720+
// This includes both inline references and discovered references (via MCPServers)
1721+
if r.vmcpReferencesExternalAuthConfig(ctx, &vmcp, externalAuthConfig.Name) {
17211722
requests = append(requests, reconcile.Request{
17221723
NamespacedName: types.NamespacedName{
17231724
Name: vmcp.Name,
@@ -1773,15 +1774,18 @@ func (*VirtualMCPServerReconciler) vmcpReferencesToolConfig(vmcp *mcpv1alpha1.Vi
17731774
return false
17741775
}
17751776

1776-
// vmcpReferencesExternalAuthConfig checks if a VirtualMCPServer references the given MCPExternalAuthConfig
1777-
func (*VirtualMCPServerReconciler) vmcpReferencesExternalAuthConfig(
1777+
// vmcpReferencesExternalAuthConfig checks if a VirtualMCPServer references the given MCPExternalAuthConfig.
1778+
// It checks both inline references (in outgoingAuth spec) and discovered references (via MCPServers in the group).
1779+
func (r *VirtualMCPServerReconciler) vmcpReferencesExternalAuthConfig(
1780+
ctx context.Context,
17781781
vmcp *mcpv1alpha1.VirtualMCPServer,
17791782
authConfigName string,
17801783
) bool {
17811784
if vmcp.Spec.OutgoingAuth == nil {
17821785
return false
17831786
}
17841787

1788+
// Check inline references in outgoing auth configuration
17851789
// Check default backend auth configuration
17861790
if vmcp.Spec.OutgoingAuth.Default != nil &&
17871791
vmcp.Spec.OutgoingAuth.Default.ExternalAuthConfigRef != nil &&
@@ -1797,6 +1801,60 @@ func (*VirtualMCPServerReconciler) vmcpReferencesExternalAuthConfig(
17971801
}
17981802
}
17991803

1804+
// Check discovered references when source is "discovered"
1805+
// When using discovered mode, auth configs are referenced through MCPServers, not inline
1806+
if vmcp.Spec.OutgoingAuth.Source == OutgoingAuthSourceDiscovered {
1807+
if r.mcpGroupBackendsReferenceExternalAuthConfig(ctx, vmcp, authConfigName) {
1808+
return true
1809+
}
1810+
}
1811+
1812+
return false
1813+
}
1814+
1815+
// mcpGroupBackendsReferenceExternalAuthConfig checks if any MCPServers in the VirtualMCPServer's group
1816+
// reference the given MCPExternalAuthConfig
1817+
func (r *VirtualMCPServerReconciler) mcpGroupBackendsReferenceExternalAuthConfig(
1818+
ctx context.Context,
1819+
vmcp *mcpv1alpha1.VirtualMCPServer,
1820+
authConfigName string,
1821+
) bool {
1822+
// Get the MCPGroup to verify it exists
1823+
mcpGroup := &mcpv1alpha1.MCPGroup{}
1824+
err := r.Get(ctx, types.NamespacedName{
1825+
Name: vmcp.Spec.GroupRef.Name,
1826+
Namespace: vmcp.Namespace,
1827+
}, mcpGroup)
1828+
if err != nil {
1829+
// If we can't get the group, we can't determine if it references the auth config
1830+
// Return false to avoid false positives
1831+
log.FromContext(ctx).Error(err, "Failed to get MCPGroup for ExternalAuthConfig reference check",
1832+
"group", vmcp.Spec.GroupRef.Name,
1833+
"vmcp", vmcp.Name)
1834+
return false
1835+
}
1836+
1837+
// List all MCPServers in the group using field selector (same as MCPGroup controller)
1838+
mcpServerList := &mcpv1alpha1.MCPServerList{}
1839+
listOpts := []client.ListOption{
1840+
client.InNamespace(vmcp.Namespace),
1841+
client.MatchingFields{"spec.groupRef": mcpGroup.Name},
1842+
}
1843+
err = r.List(ctx, mcpServerList, listOpts...)
1844+
if err != nil {
1845+
log.FromContext(ctx).Error(err, "Failed to list MCPServers for ExternalAuthConfig reference check",
1846+
"group", mcpGroup.Name)
1847+
return false
1848+
}
1849+
1850+
// Check if any MCPServer references the ExternalAuthConfig
1851+
for _, mcpServer := range mcpServerList.Items {
1852+
if mcpServer.Spec.ExternalAuthConfigRef != nil &&
1853+
mcpServer.Spec.ExternalAuthConfigRef.Name == authConfigName {
1854+
return true
1855+
}
1856+
}
1857+
18001858
return false
18011859
}
18021860

0 commit comments

Comments
 (0)