Skip to content

Commit 596903f

Browse files
committed
metamcp: reconcile STDIO servers when updateExisting=true (env, command, args); bump to 0.1.25
1 parent 0bacbc2 commit 596903f

File tree

2 files changed

+53
-25
lines changed

2 files changed

+53
-25
lines changed

charts/metamcp/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ apiVersion: v2
22
name: metamcp
33
description: MetaMCP aggregator Helm chart for Kubernetes
44
type: application
5-
version: 0.1.24
5+
version: 0.1.25
66
appVersion: "latest"
77
icon: https://icoretech.github.io/helm/charts/metamcp/logo.png
88
keywords:

charts/metamcp/scripts/provision.py

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,32 @@ def k8s_get_configmap_data(name: str):
193193
if st in ('SSE','STREAMABLE'):
194194
st = 'SSE' if st=='SSE' else 'STREAMABLE_HTTP'
195195
body = {'name': name, 'type': st}
196+
# Pre-compute desired fields for STDIO so we can also update existing servers
197+
desired_cmd = None
198+
desired_args = None
199+
desired_env = None
200+
if st == 'STDIO':
201+
cmd = s.get('command')
202+
args = s.get('args') or []
203+
if isinstance(cmd, list) and len(cmd) > 0:
204+
desired_cmd = cmd[0]
205+
desired_args = (args + cmd[1:]) if isinstance(args, list) else cmd[1:]
206+
elif isinstance(cmd, str):
207+
desired_cmd = cmd
208+
if isinstance(args, list) and args:
209+
desired_args = args
210+
env_map = {}
211+
if s.get('env') and isinstance(s['env'], dict):
212+
env_map.update({k:str(v) for k,v in s['env'].items()})
213+
for src in (s.get('envFrom') or []):
214+
if not isinstance(src, dict):
215+
continue
216+
if 'secretRef' in src and isinstance(src['secretRef'], dict) and src['secretRef'].get('name'):
217+
env_map.update(k8s_get_secret_data(src['secretRef']['name']))
218+
if 'configMapRef' in src and isinstance(src['configMapRef'], dict) and src['configMapRef'].get('name'):
219+
env_map.update(k8s_get_configmap_data(src['configMapRef']['name']))
220+
if env_map:
221+
desired_env = env_map
196222
desired_url = None
197223
if st in ('SSE','STREAMABLE_HTTP'):
198224
desired_url = s.get('url')
@@ -231,7 +257,7 @@ def k8s_get_configmap_data(name: str):
231257
if s.get('headers'):
232258
body['headers'] = s['headers']
233259

234-
# If server exists and updates are allowed, patch safe fields for HTTP/SSE
260+
# If server exists and updates are allowed, patch safe fields
235261
if name in srv_map:
236262
if UPDATE_EXISTING and st in ('SSE','STREAMABLE_HTTP'):
237263
try:
@@ -255,31 +281,33 @@ def k8s_get_configmap_data(name: str):
255281
log(f"WARN server update {name} -> {r.status_code}: {r.text[:160]}")
256282
except Exception:
257283
pass
284+
elif UPDATE_EXISTING and st == 'STDIO':
285+
try:
286+
current = srv_info.get(name, {})
287+
patch = {'uuid': current.get('uuid'), 'name': name, 'type': st}
288+
changed = False
289+
if desired_cmd is not None and (current.get('command') or '') != desired_cmd:
290+
patch['command'] = desired_cmd; changed = True
291+
if desired_args is not None and (current.get('args') or []) != desired_args:
292+
patch['args'] = desired_args; changed = True
293+
if desired_env is not None and (current.get('env') or {}) != desired_env:
294+
patch['env'] = desired_env; changed = True
295+
if changed:
296+
r = trpc_post('/trpc/frontend/frontend.mcpServers.update', patch)
297+
if r.ok:
298+
log(f"server updated: {name}")
299+
else:
300+
log(f"WARN server update {name} -> {r.status_code}: {r.text[:160]}")
301+
except Exception:
302+
pass
258303
continue
259304
if st == 'STDIO':
260-
cmd = s.get('command')
261-
args = s.get('args') or []
262-
if isinstance(cmd, list) and len(cmd) > 0:
263-
body['command'] = cmd[0]
264-
body['args'] = (args + cmd[1:]) if isinstance(args, list) else cmd[1:]
265-
elif isinstance(cmd, str):
266-
body['command'] = cmd
267-
if isinstance(args, list) and args:
268-
body['args'] = args
269-
env_map = {}
270-
if s.get('env') and isinstance(s['env'], dict):
271-
env_map.update({k:str(v) for k,v in s['env'].items()})
272-
# STDIO envFrom: resolve Secrets/ConfigMaps into env for MetaMCP-registered servers
273-
# Resolve envFrom (Secrets/ConfigMaps): pull all key=val pairs into env
274-
for src in (s.get('envFrom') or []):
275-
if not isinstance(src, dict):
276-
continue
277-
if 'secretRef' in src and isinstance(src['secretRef'], dict) and src['secretRef'].get('name'):
278-
env_map.update(k8s_get_secret_data(src['secretRef']['name']))
279-
if 'configMapRef' in src and isinstance(src['configMapRef'], dict) and src['configMapRef'].get('name'):
280-
env_map.update(k8s_get_configmap_data(src['configMapRef']['name']))
281-
if env_map:
282-
body['env'] = env_map
305+
if desired_cmd is not None:
306+
body['command'] = desired_cmd
307+
if desired_args is not None:
308+
body['args'] = desired_args
309+
if desired_env is not None:
310+
body['env'] = desired_env
283311
r = trpc_post('/trpc/frontend/frontend.mcpServers.create', body)
284312
if r.ok:
285313
try:

0 commit comments

Comments
 (0)