1
+ import { KubernetesManager } from "../types.js" ;
2
+ import * as k8s from "@kubernetes/client-node" ;
3
+ import { McpError , ErrorCode } from "@modelcontextprotocol/sdk/types.js" ;
4
+ import {
5
+ ContainerTemplate ,
6
+ containerTemplates ,
7
+ CustomContainerConfig ,
8
+ CustomContainerConfigType ,
9
+ } from "../config/container-templates.js" ;
10
+
11
+ export const updateDeploymentSchema = {
12
+ name : "update_deployment" ,
13
+ description : "Update an existing kubernetes deployment in cluster" ,
14
+ inputSchema : {
15
+ type : "object" ,
16
+ required : [ "name" , "namespace" , "template" ] ,
17
+ properties : {
18
+ name : { type : "string" } ,
19
+ namespace : { type : "string" } ,
20
+ template : {
21
+ type : "string" ,
22
+ enum : ContainerTemplate . options ,
23
+ } ,
24
+ containerName : {
25
+ type : "string" ,
26
+ description : "Name of the container to update" ,
27
+ } ,
28
+ replicas : { type : "number" } ,
29
+ customConfig : {
30
+ type : "object" ,
31
+ properties : {
32
+ image : { type : "string" } ,
33
+ command : { type : "array" , items : { type : "string" } } ,
34
+ args : { type : "array" , items : { type : "string" } } ,
35
+ ports : {
36
+ type : "array" ,
37
+ items : {
38
+ type : "object" ,
39
+ properties : {
40
+ containerPort : { type : "number" } ,
41
+ name : { type : "string" } ,
42
+ protocol : { type : "string" } ,
43
+ } ,
44
+ } ,
45
+ } ,
46
+ resources : {
47
+ type : "object" ,
48
+ properties : {
49
+ limits : {
50
+ type : "object" ,
51
+ additionalProperties : { type : "string" } ,
52
+ } ,
53
+ requests : {
54
+ type : "object" ,
55
+ additionalProperties : { type : "string" } ,
56
+ } ,
57
+ } ,
58
+ } ,
59
+ env : {
60
+ type : "array" ,
61
+ items : {
62
+ type : "object" ,
63
+ properties : {
64
+ name : { type : "string" } ,
65
+ value : { type : "string" } ,
66
+ valueFrom : { type : "object" } ,
67
+ } ,
68
+ } ,
69
+ } ,
70
+ } ,
71
+ } ,
72
+ } ,
73
+ } ,
74
+ } ;
75
+
76
+ export async function updateDeployment (
77
+ k8sManager : KubernetesManager ,
78
+ params : {
79
+ name : string ;
80
+ namespace : string ;
81
+ template : string ;
82
+ containerName ?: string ;
83
+ replicas ?: number ;
84
+ customConfig ?: CustomContainerConfigType ;
85
+ }
86
+ ) {
87
+ // Get existing deployment
88
+ const { body : existingDeployment } = await k8sManager
89
+ . getAppsApi ( )
90
+ . readNamespacedDeployment ( params . name , params . namespace )
91
+ . catch ( ( error : any ) => {
92
+ console . error ( "Deployment read error:" , {
93
+ status : error . response ?. statusCode ,
94
+ message : error . response ?. body ?. message || error . message ,
95
+ details : error . response ?. body ,
96
+ } ) ;
97
+ throw error ;
98
+ } ) ;
99
+
100
+ // Find target container
101
+ const containers = existingDeployment . spec ! . template . spec ! . containers ;
102
+ let targetContainerIndex = params . containerName
103
+ ? containers . findIndex ( c => c . name === params . containerName )
104
+ : 0 ;
105
+
106
+ if ( targetContainerIndex === - 1 ) {
107
+ throw new McpError (
108
+ ErrorCode . InvalidRequest ,
109
+ `Container '${ params . containerName } ' not found in deployment`
110
+ ) ;
111
+ }
112
+
113
+ // Prepare container config
114
+ const templateConfig = containerTemplates [ params . template ] ;
115
+ let containerConfig : k8s . V1Container ;
116
+
117
+ if ( params . template === "custom" ) {
118
+ if ( ! params . customConfig ) {
119
+ throw new McpError (
120
+ ErrorCode . InvalidRequest ,
121
+ "Custom container configuration is required when using 'custom' template"
122
+ ) ;
123
+ }
124
+
125
+ const validatedConfig = CustomContainerConfig . parse ( params . customConfig ) ;
126
+ containerConfig = {
127
+ ...containers [ targetContainerIndex ] ,
128
+ ...templateConfig ,
129
+ image : validatedConfig . image ,
130
+ command : validatedConfig . command ,
131
+ args : validatedConfig . args ,
132
+ ports : validatedConfig . ports ,
133
+ resources : validatedConfig . resources ,
134
+ env : validatedConfig . env ,
135
+ } ;
136
+ } else {
137
+ containerConfig = {
138
+ ...containers [ targetContainerIndex ] ,
139
+ ...templateConfig ,
140
+ } ;
141
+ }
142
+
143
+ // Update deployment
144
+ const updatedContainers = [ ...containers ] ;
145
+ updatedContainers [ targetContainerIndex ] = containerConfig ;
146
+
147
+ const updatedDeployment : k8s . V1Deployment = {
148
+ ...existingDeployment ,
149
+ spec : {
150
+ ...existingDeployment . spec ! ,
151
+ replicas : params . replicas ?? existingDeployment . spec ! . replicas ,
152
+ template : {
153
+ ...existingDeployment . spec ! . template ,
154
+ spec : {
155
+ ...existingDeployment . spec ! . template . spec ,
156
+ containers : updatedContainers ,
157
+ } ,
158
+ } ,
159
+ } ,
160
+ } ;
161
+
162
+ const { body } = await k8sManager
163
+ . getAppsApi ( )
164
+ . replaceNamespacedDeployment ( params . name , params . namespace , updatedDeployment )
165
+ . catch ( ( error ) => {
166
+ if ( error instanceof McpError ) throw error ;
167
+ throw new McpError (
168
+ ErrorCode . InternalError ,
169
+ `Failed to update deployment: ${ error } `
170
+ ) ;
171
+ } )
172
+ return {
173
+ content : [
174
+ {
175
+ type : "text" ,
176
+ text : JSON . stringify (
177
+ {
178
+ message : "Deployment updated successfully" ,
179
+ deployment : {
180
+ name : body . metadata ?. name ,
181
+ namespace : body . metadata ?. namespace ,
182
+ replicas : body . spec ?. replicas ,
183
+ image : body . spec ?. template . spec ?. containers [ targetContainerIndex ] . image ,
184
+ containerName : body . spec ?. template . spec ?. containers [ targetContainerIndex ] . name ,
185
+ } ,
186
+ } ,
187
+ null ,
188
+ 2
189
+ ) ,
190
+ } ,
191
+ ] ,
192
+ } ;
193
+ }
0 commit comments