Skip to content

Commit 1ff3186

Browse files
committed
fix: handle argument value replacement with more patterns
1 parent 2432b3b commit 1ff3186

File tree

1 file changed

+56
-3
lines changed
  • src/mcpm/commands/server_operations

1 file changed

+56
-3
lines changed

src/mcpm/commands/server_operations/add.py

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,13 +344,16 @@ def add(server_name, force=False, alias=None, target: str | None = None):
344344

345345
# replace arguments with values
346346
processed_args = []
347-
for arg in install_args:
348-
processed_args.append(_replace_variables(arg, processed_variables))
347+
for i, arg in enumerate(install_args):
348+
prev_arg = install_args[i - 1] if i > 0 else ""
349+
# handles arguments with pattern var=${var} | --var=var | --var var
350+
processed_args.append(_replace_argument_variables(arg, prev_arg, processed_variables))
349351

350352
# process environment variables
351353
processed_env = {}
352354
for key, value in env_vars.items():
353-
processed_env[key] = _replace_variables(value, processed_variables)
355+
# just replace the env value regardless of the variable pattern, ${VAR}/YOUR_VAR/VAR
356+
processed_env[key] = processed_variables.get(key, value)
354357

355358
# Get actual MCP execution command, args, and env from the selected installation method
356359
# This ensures we use the actual server command information instead of placeholders
@@ -433,3 +436,53 @@ def _replace_variables(value: str, variables: dict) -> str:
433436
# Use empty string as default when key not found
434437
return value.replace(original, variables.get(var_name, ""))
435438
return value
439+
440+
441+
def _replace_argument_variables(value: str, prev_value: str, variables: dict) -> str:
442+
"""Replace variables in command-line arguments with values from variables dictionary.
443+
444+
Handles four argument formats:
445+
1. Variable substitution: argument=${VAR_NAME}
446+
2. Key-value pair: --argument=value
447+
3. Space-separated pair: --argument value (where prev_value represents --argument)
448+
449+
Args:
450+
value: The current argument string that may contain variables
451+
prev_value: The previous argument string (for space-separated pairs)
452+
variables: Dictionary mapping variable names to their values
453+
454+
Returns:
455+
String with all variables replaced with their values from the variables dict
456+
"""
457+
if not isinstance(value, str):
458+
return value
459+
460+
# arg: VAR=${VAR}
461+
# check if the value contains a variable
462+
matched = re.search(r"\$\{([^}]+)\}", value)
463+
if matched:
464+
original, var_name = matched.group(0), matched.group(1)
465+
# Use empty string as default when key not found
466+
return value.replace(original, variables.get(var_name, ""))
467+
468+
# arg: --VAR=your var value
469+
key_value_match = re.match(r"^([A-Z_]+)=(.+)$", value)
470+
if key_value_match:
471+
arg_key = key_value_match.group(1)
472+
if arg_key in variables:
473+
# replace the arg_value with variables[arg_key]
474+
return f"{arg_key}={variables[arg_key]}"
475+
# if not contains the arg_key then just return the original value
476+
return value
477+
478+
# arg: --VAR your_var_value
479+
if prev_value.startswith("--") or prev_value.startswith("-"):
480+
arg_key = prev_value.lstrip("-")
481+
if arg_key in variables:
482+
# replace the value with variables[arg_key]
483+
return variables[arg_key]
484+
# if not contains the arg_key then just return the original value
485+
return value
486+
487+
# nothing to replace
488+
return value

0 commit comments

Comments
 (0)