@@ -357,8 +357,7 @@ func (r *MCPServerReconciler) ensureRBACResources(ctx context.Context, mcpServer
357
357
return err
358
358
}
359
359
360
- // Ensure RoleBinding
361
- return r .ensureRBACResource (ctx , mcpServer , "RoleBinding" , func () client.Object {
360
+ if err := r .ensureRBACResource (ctx , mcpServer , "RoleBinding" , func () client.Object {
362
361
return & rbacv1.RoleBinding {
363
362
ObjectMeta : metav1.ObjectMeta {
364
363
Name : proxyRunnerNameForRBAC ,
@@ -377,6 +376,25 @@ func (r *MCPServerReconciler) ensureRBACResources(ctx context.Context, mcpServer
377
376
},
378
377
},
379
378
}
379
+ }); err != nil {
380
+ return err
381
+ }
382
+
383
+ // If a service account is specified, we don't need to create one
384
+ if mcpServer .Spec .ServiceAccount != nil {
385
+ return nil
386
+ }
387
+
388
+ // otherwise, create a service account for the MCP server
389
+ mcpServerServiceAccountName := mcpServerServiceAccountName (mcpServer .Name )
390
+ return r .ensureRBACResource (ctx , mcpServer , "ServiceAccount" , func () client.Object {
391
+ mcpServer .Spec .ServiceAccount = & mcpServerServiceAccountName
392
+ return & corev1.ServiceAccount {
393
+ ObjectMeta : metav1.ObjectMeta {
394
+ Name : mcpServerServiceAccountName ,
395
+ Namespace : mcpServer .Namespace ,
396
+ },
397
+ }
380
398
})
381
399
}
382
400
@@ -399,8 +417,11 @@ func (r *MCPServerReconciler) deploymentForMCPServer(m *mcpv1alpha1.MCPServer) *
399
417
}
400
418
401
419
// Generate pod template patch for secrets and merge with user-provided patch
402
- finalPodTemplateSpec := generateAndMergePodTemplateSpecs (m .Spec .Secrets , m .Spec .PodTemplateSpec )
403
420
421
+ finalPodTemplateSpec := NewMCPServerPodTemplateSpecBuilder (m .Spec .PodTemplateSpec ).
422
+ WithServiceAccount (m .Spec .ServiceAccount ).
423
+ WithSecrets (m .Spec .Secrets ).
424
+ Build ()
404
425
// Add pod template patch if we have one
405
426
if finalPodTemplateSpec != nil {
406
427
podTemplatePatch , err := json .Marshal (finalPodTemplateSpec )
@@ -941,7 +962,10 @@ func deploymentNeedsUpdate(deployment *appsv1.Deployment, mcpServer *mcpv1alpha1
941
962
}
942
963
943
964
// Check if the pod template spec has changed (including secrets)
944
- expectedPodTemplateSpec := generateAndMergePodTemplateSpecs (mcpServer .Spec .Secrets , mcpServer .Spec .PodTemplateSpec )
965
+ expectedPodTemplateSpec := NewMCPServerPodTemplateSpecBuilder (mcpServer .Spec .PodTemplateSpec ).
966
+ WithServiceAccount (mcpServer .Spec .ServiceAccount ).
967
+ WithSecrets (mcpServer .Spec .Secrets ).
968
+ Build ()
945
969
946
970
// Find the current pod template patch in the container args
947
971
var currentPodTemplatePatch string
@@ -1089,6 +1113,11 @@ func proxyRunnerServiceAccountName(mcpServerName string) string {
1089
1113
return fmt .Sprintf ("%s-proxy-runner" , mcpServerName )
1090
1114
}
1091
1115
1116
+ // mcpServerServiceAccountName returns the service account name for the mcp server
1117
+ func mcpServerServiceAccountName (mcpServerName string ) string {
1118
+ return fmt .Sprintf ("%s-sa" , mcpServerName )
1119
+ }
1120
+
1092
1121
// labelsForMCPServer returns the labels for selecting the resources
1093
1122
// belonging to the given MCPServer CR name.
1094
1123
func labelsForMCPServer (name string ) map [string ]string {
@@ -1511,103 +1540,6 @@ func int32Ptr(i int32) *int32 {
1511
1540
return & i
1512
1541
}
1513
1542
1514
- // generateSecretsPodTemplatePatch generates a podTemplateSpec patch for secrets
1515
- func generateSecretsPodTemplatePatch (secrets []mcpv1alpha1.SecretRef ) * corev1.PodTemplateSpec {
1516
- if len (secrets ) == 0 {
1517
- return nil
1518
- }
1519
-
1520
- envVars := make ([]corev1.EnvVar , 0 , len (secrets ))
1521
- for _ , secret := range secrets {
1522
- targetEnv := secret .Key
1523
- if secret .TargetEnvName != "" {
1524
- targetEnv = secret .TargetEnvName
1525
- }
1526
-
1527
- envVars = append (envVars , corev1.EnvVar {
1528
- Name : targetEnv ,
1529
- ValueFrom : & corev1.EnvVarSource {
1530
- SecretKeyRef : & corev1.SecretKeySelector {
1531
- LocalObjectReference : corev1.LocalObjectReference {
1532
- Name : secret .Name ,
1533
- },
1534
- Key : secret .Key ,
1535
- },
1536
- },
1537
- })
1538
- }
1539
-
1540
- return & corev1.PodTemplateSpec {
1541
- Spec : corev1.PodSpec {
1542
- Containers : []corev1.Container {
1543
- {
1544
- Name : mcpContainerName ,
1545
- Env : envVars ,
1546
- },
1547
- },
1548
- },
1549
- }
1550
- }
1551
-
1552
- // mergePodTemplateSpecs merges a secrets patch with a user-provided podTemplateSpec
1553
- func mergePodTemplateSpecs (secretsPatch , userPatch * corev1.PodTemplateSpec ) * corev1.PodTemplateSpec {
1554
- // If no secrets, return user patch as-is
1555
- if secretsPatch == nil {
1556
- return userPatch
1557
- }
1558
-
1559
- // If no user patch, return secrets patch
1560
- if userPatch == nil {
1561
- return secretsPatch
1562
- }
1563
-
1564
- // Start with user patch as base (preserves all user customizations)
1565
- result := userPatch .DeepCopy ()
1566
-
1567
- // Find or create mcp container in result
1568
- mcpIndex := - 1
1569
- for i , container := range result .Spec .Containers {
1570
- if container .Name == mcpContainerName {
1571
- mcpIndex = i
1572
- break
1573
- }
1574
- }
1575
-
1576
- // Get secret env vars from secrets patch
1577
- var secretEnvVars []corev1.EnvVar
1578
- for _ , container := range secretsPatch .Spec .Containers {
1579
- if container .Name == mcpContainerName {
1580
- secretEnvVars = container .Env
1581
- break
1582
- }
1583
- }
1584
-
1585
- if mcpIndex >= 0 {
1586
- // Merge env vars into existing mcp container
1587
- result .Spec .Containers [mcpIndex ].Env = append (
1588
- result .Spec .Containers [mcpIndex ].Env ,
1589
- secretEnvVars ... ,
1590
- )
1591
- } else {
1592
- // Add new mcp container with just env vars
1593
- result .Spec .Containers = append (result .Spec .Containers , corev1.Container {
1594
- Name : mcpContainerName ,
1595
- Env : secretEnvVars ,
1596
- })
1597
- }
1598
-
1599
- return result
1600
- }
1601
-
1602
- // generateAndMergePodTemplateSpecs generates secrets patch and merges with user patch
1603
- func generateAndMergePodTemplateSpecs (
1604
- secrets []mcpv1alpha1.SecretRef ,
1605
- userPatch * corev1.PodTemplateSpec ,
1606
- ) * corev1.PodTemplateSpec {
1607
- secretsPatch := generateSecretsPodTemplatePatch (secrets )
1608
- return mergePodTemplateSpecs (secretsPatch , userPatch )
1609
- }
1610
-
1611
1543
// SetupWithManager sets up the controller with the Manager.
1612
1544
func (r * MCPServerReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
1613
1545
return ctrl .NewControllerManagedBy (mgr ).
0 commit comments