fix for auto installer package config. and disable servers if they encounter setup errors without crashing container
deci committed
May 22, 2025 at 07:06 UTC
e3b75b159f67d8e9f36ae2d62c1e11fabb4c5704
1 file changed
+80
-20
initialize.py
+80
-20
@@ -32,34 +32,42 @@ def _ensure_mcp_package_globally_installed(package_name: str, executable_name: s
32
PrintStyle(font_color="green", padding=True).print(
33
f"'{executable_name}' is now available in PATH after install."
34
)
35
+ return True # Successfully installed and found
36
else:
37
PrintStyle(font_color="orange", padding=True).print(
38
f"WARNING: npm install of '{package_name}' reported success, but '{executable_name}' still not found in PATH. " +
39
"The 'npx' command in settings.json might still be necessary or there might be an issue with PATH."
40
)
41
+ return False # Install reported success, but executable not found
42
else:
43
PrintStyle(font_color="red", padding=True).print(
44
f"Failed to install '{package_name}' globally via npm. Return code: {process.returncode}"
45
)
46
PrintStyle(font_color="red", padding=False).print(f"npm stdout: {process.stdout.strip()}")
47
PrintStyle(font_color="red", padding=False).print(f"npm stderr: {process.stderr.strip()}")
48
+ return False # Install failed
49
except FileNotFoundError:
50
PrintStyle(font_color="red", padding=True).print(
51
f"ERROR: 'npm' command not found. Cannot attempt to install '{package_name}'."
52
)
53
+ return False # npm not found
54
except Exception as e:
55
PrintStyle(font_color="red", padding=True).print(
56
f"Exception during npm install of '{package_name}': {e}"
57
)
58
+ return False # Other exception during install
59
else:
60
PrintStyle(font_color="green", padding=True).print(
61
f"'{executable_name}' (from package '{package_name}') already found in PATH."
62
)
63
+ return True # Already found in PATH
64
else:
65
PrintStyle(font_color="red", padding=True).print(
66
f"ERROR: 'npm' command not found. Cannot check for or install '{executable_name}' from '{package_name}'."
67
)
62
- # PrintStyle().print() # For a blank line after each attempt
68
+ return False # npm command not found, cannot check or install
69
+ # Fallback, though logic above should cover all paths to return explicitly
70
+ return False
71
72
73
def initialize():
@@ -93,31 +101,83 @@ def initialize():
101
args = server_config.get("args", [])
102
server_name = server_config.get("name", "Unknown MCP Server")
103
96
- if command == "npx" and "--package" in args:
97
- try:
98
- package_keyword_index = args.index("--package")
99
- # Expect package name at +1 and executable name at +2 from "--package"
100
- if package_keyword_index + 2 < len(args):
101
- package_name = args[package_keyword_index + 1]
102
- executable_name = args[package_keyword_index + 2]
103
- if package_name and executable_name: # Ensure they are not empty strings
104
- _ensure_mcp_package_globally_installed(package_name, executable_name)
104
+ if command == "npx":
105
+ package_name_for_install = None
106
+ executable_name_to_check = None
107
+
108
+ if "--package" in args: # Original logic for npx --package <pkg> <exec>
109
+ try:
110
+ package_keyword_index = args.index("--package")
111
+ # Expect package name at +1 and executable name at +2 from "--package"
112
+ if package_keyword_index + 2 < len(args):
113
+ package_name_for_install = args[package_keyword_index + 1]
114
+ executable_name_to_check = args[package_keyword_index + 2]
115
else:
116
PrintStyle(font_color="orange", padding=True).print(
107
- f"Warning: Skipping MCP server '{server_name}' due to empty package or executable name extracted from args: {args}"
117
+ f"Warning: Skipping MCP server '{server_name}' (npx --package) as package or executable name could not be determined from args: {args}"
118
)
119
+ except ValueError: # Should not happen if "--package" is in args, but good for safety
120
+ PrintStyle(font_color="orange", padding=True).print(
121
+ f"Warning: '--package' keyword found but .index() failed for args: {args} in server '{server_name}'"
122
+ )
123
+ except Exception as e:
124
+ PrintStyle(font_color="red", padding=True).print(
125
+ f"Error processing npx --package args for server '{server_name}': {e}. Args: {args}"
126
+ )
127
+ else: # New logic for npx <pkg_arg> syntax
128
+ parsed_npx_pkg_arg = None
129
+ arg_idx = 0
130
+ while arg_idx < len(args):
131
+ current_arg = args[arg_idx]
132
+ # npx's own -p/--package option for temporary installs, distinct from the --package marker we check above
133
+ if current_arg == "-p" or current_arg == "--package":
134
+ arg_idx += 1 # Move to the value of -p/--package
135
+ if arg_idx < len(args): # Ensure there is a value
136
+ arg_idx += 1 # Skip the value itself
137
+ continue
138
+
139
+ if current_arg.startswith("-"): # Skip other options like -y, --yes, --no-install etc.
140
+ arg_idx += 1
141
+ continue
142
+
143
+ # Found what we assume is the main package argument for npx
144
+ parsed_npx_pkg_arg = current_arg
145
+ break # Found the package, stop parsing args for this purpose
146
+
147
+ if parsed_npx_pkg_arg:
148
+ package_name_for_install = parsed_npx_pkg_arg
149
+ # Derive assumed executable name based on convention from error: "mcp-server-google-maps" for "@.../server-google-maps"
150
+ # For "@scope/pkg-name" -> "pkg-name". For "pkg-name" -> "pkg-name".
151
+ name_part = parsed_npx_pkg_arg.split("/")[-1]
152
+ executable_name_to_check = f"mcp-{name_part}"
153
+ PrintStyle(font_color="blue", padding=True).print(
154
+ f"Info: For MCP server '{server_name}' (npx <pkg_arg> type), attempting to ensure global install of package '{package_name_for_install}' and expecting executable '{executable_name_to_check}'."
155
+ )
156
else:
157
PrintStyle(font_color="orange", padding=True).print(
111
- f"Warning: Skipping MCP server '{server_name}' as package name or executable name could not be determined from args: {args}"
158
+ f"Warning: Skipping MCP server '{server_name}' (npx <pkg_arg> type) as main package argument could not be identified from args: {args}"
159
)
113
- except ValueError: # Should not happen if "--package" is in args, but good for safety
114
- PrintStyle(font_color="orange", padding=True).print(
115
- f"Warning: '--package' keyword found but .index() failed for args: {args} in server '{server_name}'"
116
- )
117
- except Exception as e:
118
- PrintStyle(font_color="red", padding=True).print(
119
- f"Error processing npx args for server '{server_name}': {e}. Args: {args}"
120
- )
160
+
161
+ # Unified call to ensure package is installed
162
+ if package_name_for_install and executable_name_to_check:
163
+ # Ensure they are not empty strings or just whitespace
164
+ if package_name_for_install.strip() and executable_name_to_check.strip():
165
+ install_successful = _ensure_mcp_package_globally_installed(package_name_for_install.strip(), executable_name_to_check.strip())
166
+ if not install_successful:
167
+ PrintStyle(font_color="red", padding=True).print(
168
+ f"Disabling MCP server '{server_name}' due to failed setup/validation for package '{package_name_for_install}' and/or executable '{executable_name_to_check}'."
169
+ )
170
+ server_config["disabled"] = True # Disable this server config
171
+ else:
172
+ PrintStyle(font_color="orange", padding=True).print(
173
+ f"Warning: Skipping MCP server '{server_name}' due to empty package or executable name derived: pkg='{package_name_for_install}', exec='{executable_name_to_check}' from args: {args}. Not attempting install."
174
+ )
175
+ # Optionally, consider if these should also be marked as disabled,
176
+ # though current logic implies they weren't valid enough to attempt install.
177
+ # server_config["disabled"] = True
178
+ # If package_name_for_install or executable_name_to_check are None or empty,
179
+ # it means previous logic decided not to proceed or couldn't determine them,
180
+ # and appropriate warnings would have been printed.
181
else:
182
PrintStyle(font_color="red", padding=True).print(
183
"ERROR: 'npm' command not found. Cannot attempt to install any MCP server packages."