Skip to content

Commit 455dd4a

Browse files
authored
feat(mcpserver): add ServiceAccount annotations and labels support (#95)
# Add ServiceAccount customization support for MCPServer ## Overview This PR adds support for customizing ServiceAccount annotations and labels in MCPServer resources, enabling cloud provider integrations such as AWS IRSA (IAM Roles for Service Accounts). ## Motivation Currently, MCPServers create ServiceAccounts with only basic metadata. To enable cloud provider integrations (AWS IRSA, GCP Workload Identity, Azure Managed Identity), users need the ability to add custom annotations and labels to these ServiceAccounts. ## Changes ### 1. API Changes (`api/v1alpha1/mcpserver_types.go`) - Added `ServiceAccountConfig` type with: - `Annotations map[string]string` - for cloud provider annotations (e.g., AWS IRSA role ARN) - `Labels map[string]string` - for resource organization and policy enforcement - Added `ServiceAccount *ServiceAccountConfig` field to `MCPServerDeployment` - Comprehensive documentation with examples ### 2. Controller Changes (`pkg/controller/transportadapter/transportadapter_translator.go`) - Modified `translateTransportAdapterServiceAccount()` to apply custom annotations and labels - Maintains backward compatibility (defaults when not specified) ### 3. CRD Updates - Generated updated CRD with new fields and validation - Updated deepcopy code ### 4. Documentation - Added example file: `config/samples/mcpserver-serviceaccount-irsa.yaml` - Shows complete AWS IRSA configuration example ## Use Cases ### AWS IRSA (IAM Roles for Service Accounts) ```yaml spec: deployment: serviceAccount: annotations: eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/my-role" eks.amazonaws.com/sts-regional-endpoints: "true" labels: team: platform environment: production ``` Enables MCPServer pods to: - Access AWS services (S3, DynamoDB, Secrets Manager, etc.) without managing credentials - Use temporary IAM credentials automatically refreshed by AWS - Follow AWS security best practices (no long-lived credentials) ## Backward Compatibility ✅ **Fully backward compatible**: - All new fields are optional (`omitempty`) - Existing MCPServer resources continue working unchanged - Default behavior preserved when fields not specified ## Testing - [x] Code compiles successfully - [x] `make generate` updates deepcopy code - [x] `make manifests` generates valid CRDs - [x] `make test` passes all unit tests - [x] Example manifest validates configuration ## Checklist - [x] API changes documented with clear comments - [x] Controller implementation tested - [x] CRDs regenerated - [x] Example file provided - [x] Backward compatibility maintained - [x] Commit signed with DCO ## Migration Notes No migration required. This is an additive change that does not affect existing MCPServer resources. Signed-off-by: skhedim <sebastien.khedim@gmail.com> Signed-off-by: sebastien_khedim <Sebastien_KHEDIM@ext.connect-tech.sncf>
1 parent 5c40e9d commit 455dd4a

5 files changed

Lines changed: 122 additions & 4 deletions

File tree

api/v1alpha1/mcpserver_types.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ type MCPServerDeployment struct {
236236
// the transport adapter binary. This is used for stdio transport type.
237237
// +optional
238238
InitContainer *InitContainerConfig `json:"initContainer,omitempty"`
239+
240+
// ServiceAccount defines the configuration for the ServiceAccount.
241+
// +optional
242+
ServiceAccount *ServiceAccountConfig `json:"serviceAccount,omitempty"`
239243
}
240244

241245
// InitContainerConfig defines the configuration for the init container.
@@ -252,6 +256,20 @@ type InitContainerConfig struct {
252256
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
253257
}
254258

259+
// ServiceAccountConfig defines the configuration for the ServiceAccount.
260+
type ServiceAccountConfig struct {
261+
// Annotations to add to the ServiceAccount.
262+
// This is useful for configuring AWS IRSA (IAM Roles for Service Accounts)
263+
// or other cloud provider integrations.
264+
// Example: {"eks.amazonaws.com/role-arn": "arn:aws:iam::123456789012:role/my-role"}
265+
// +optional
266+
Annotations map[string]string `json:"annotations,omitempty"`
267+
268+
// Labels to add to the ServiceAccount.
269+
// +optional
270+
Labels map[string]string `json:"labels,omitempty"`
271+
}
272+
255273
// +kubebuilder:object:root=true
256274
// +kubebuilder:subresource:status
257275
// +kubebuilder:resource:shortName=mcps;mcp

api/v1alpha1/zz_generated.deepcopy.go

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

config/crd/bases/kagent.dev_mcpservers.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,25 @@ spec:
138138
type: object
139139
x-kubernetes-map-type: atomic
140140
type: array
141+
serviceAccount:
142+
description: ServiceAccount defines the configuration for the
143+
ServiceAccount.
144+
properties:
145+
annotations:
146+
additionalProperties:
147+
type: string
148+
description: |-
149+
Annotations to add to the ServiceAccount.
150+
This is useful for configuring AWS IRSA (IAM Roles for Service Accounts)
151+
or other cloud provider integrations.
152+
Example: {"eks.amazonaws.com/role-arn": "arn:aws:iam::123456789012:role/my-role"}
153+
type: object
154+
labels:
155+
additionalProperties:
156+
type: string
157+
description: Labels to add to the ServiceAccount.
158+
type: object
159+
type: object
141160
volumeMounts:
142161
description: |-
143162
VolumeMounts defines the list of volume mounts for the MCP server container.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
# Example MCPServer with ServiceAccount configuration for AWS IRSA
3+
# This demonstrates how to configure annotations and labels on the
4+
# ServiceAccount created by the MCPServer controller.
5+
#
6+
# Use case: AWS IRSA (IAM Roles for Service Accounts) authentication
7+
# The eks.amazonaws.com/role-arn annotation allows pods using this
8+
# ServiceAccount to assume an IAM role without requiring AWS credentials.
9+
apiVersion: kagent.dev/v1alpha1
10+
kind: MCPServer
11+
metadata:
12+
name: mcpserver-irsa-example
13+
namespace: default
14+
spec:
15+
deployment:
16+
image: ghcr.io/modelcontextprotocol/servers/filesystem:latest
17+
port: 3000
18+
cmd: /usr/local/bin/mcp-server-filesystem
19+
args:
20+
- /data
21+
# ServiceAccount configuration for AWS IRSA
22+
serviceAccount:
23+
annotations:
24+
# AWS IRSA annotation - replace with your IAM role ARN
25+
eks.amazonaws.com/role-arn: "arn:aws:iam::123456789012:role/my-mcp-server-role"
26+
# Optional: use regional STS endpoints
27+
eks.amazonaws.com/sts-regional-endpoints: "true"
28+
labels:
29+
# Custom labels for organization and policy enforcement
30+
team: platform
31+
component: mcp-server
32+
environment: production
33+
managed-by: kmcp
34+
transportType: stdio
35+
stdioTransport: {}

pkg/controller/transportadapter/transportadapter_translator.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -286,15 +286,27 @@ func (t *transportAdapterTranslator) addMCPServerConfigHashAnnotation(
286286
func (t *transportAdapterTranslator) translateTransportAdapterServiceAccount(
287287
server *v1alpha1.MCPServer,
288288
) (*corev1.ServiceAccount, error) {
289+
objectMeta := metav1.ObjectMeta{
290+
Name: server.Name,
291+
Namespace: server.Namespace,
292+
}
293+
294+
// Apply custom annotations and labels if provided
295+
if server.Spec.Deployment.ServiceAccount != nil {
296+
if server.Spec.Deployment.ServiceAccount.Annotations != nil {
297+
objectMeta.Annotations = server.Spec.Deployment.ServiceAccount.Annotations
298+
}
299+
if server.Spec.Deployment.ServiceAccount.Labels != nil {
300+
objectMeta.Labels = server.Spec.Deployment.ServiceAccount.Labels
301+
}
302+
}
303+
289304
serviceAccount := &corev1.ServiceAccount{
290305
TypeMeta: metav1.TypeMeta{
291306
Kind: "ServiceAccount",
292307
APIVersion: corev1.SchemeGroupVersion.String(),
293308
},
294-
ObjectMeta: metav1.ObjectMeta{
295-
Name: server.Name,
296-
Namespace: server.Namespace,
297-
},
309+
ObjectMeta: objectMeta,
298310
}
299311
return serviceAccount, controllerutil.SetOwnerReference(server, serviceAccount, t.scheme)
300312
}

0 commit comments

Comments
 (0)