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."