@@ -357,8 +357,7 @@ func (r *MCPServerReconciler) ensureRBACResources(ctx context.Context, mcpServer
357357 return err
358358 }
359359
360- // Ensure RoleBinding
361- return r .ensureRBACResource (ctx , mcpServer , "RoleBinding" , func () client.Object {
360+ if err := r .ensureRBACResource (ctx , mcpServer , "RoleBinding" , func () client.Object {
362361 return & rbacv1.RoleBinding {
363362 ObjectMeta : metav1.ObjectMeta {
364363 Name : proxyRunnerNameForRBAC ,
@@ -377,6 +376,25 @@ func (r *MCPServerReconciler) ensureRBACResources(ctx context.Context, mcpServer
377376 },
378377 },
379378 }
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+ }
380398 })
381399}
382400
@@ -399,8 +417,11 @@ func (r *MCPServerReconciler) deploymentForMCPServer(m *mcpv1alpha1.MCPServer) *
399417 }
400418
401419 // Generate pod template patch for secrets and merge with user-provided patch
402- finalPodTemplateSpec := generateAndMergePodTemplateSpecs (m .Spec .Secrets , m .Spec .PodTemplateSpec )
403420
421+ finalPodTemplateSpec := NewMCPServerPodTemplateSpecBuilder (m .Spec .PodTemplateSpec ).
422+ WithServiceAccount (m .Spec .ServiceAccount ).
423+ WithSecrets (m .Spec .Secrets ).
424+ Build ()
404425 // Add pod template patch if we have one
405426 if finalPodTemplateSpec != nil {
406427 podTemplatePatch , err := json .Marshal (finalPodTemplateSpec )
@@ -941,7 +962,10 @@ func deploymentNeedsUpdate(deployment *appsv1.Deployment, mcpServer *mcpv1alpha1
941962 }
942963
943964 // 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 ()
945969
946970 // Find the current pod template patch in the container args
947971 var currentPodTemplatePatch string
@@ -1089,6 +1113,11 @@ func proxyRunnerServiceAccountName(mcpServerName string) string {
10891113 return fmt .Sprintf ("%s-proxy-runner" , mcpServerName )
10901114}
10911115
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+
10921121// labelsForMCPServer returns the labels for selecting the resources
10931122// belonging to the given MCPServer CR name.
10941123func labelsForMCPServer (name string ) map [string ]string {
@@ -1511,103 +1540,6 @@ func int32Ptr(i int32) *int32 {
15111540 return & i
15121541}
15131542
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-
16111543// SetupWithManager sets up the controller with the Manager.
16121544func (r * MCPServerReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
16131545 return ctrl .NewControllerManagedBy (mgr ).
0 commit comments