apm-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apm_cli/__init__.py +5 -0
- apm_cli/adapters/__init__.py +1 -0
- apm_cli/adapters/client/__init__.py +1 -0
- apm_cli/adapters/client/base.py +36 -0
- apm_cli/adapters/client/vscode.py +301 -0
- apm_cli/adapters/package_manager/__init__.py +1 -0
- apm_cli/adapters/package_manager/base.py +27 -0
- apm_cli/adapters/package_manager/default_manager.py +123 -0
- apm_cli/cli.py +1415 -0
- apm_cli/compilation/__init__.py +29 -0
- apm_cli/compilation/agents_compiler.py +312 -0
- apm_cli/compilation/link_resolver.py +230 -0
- apm_cli/compilation/template_builder.py +137 -0
- apm_cli/config.py +60 -0
- apm_cli/core/__init__.py +1 -0
- apm_cli/core/operations.py +78 -0
- apm_cli/core/script_runner.py +253 -0
- apm_cli/deps/__init__.py +12 -0
- apm_cli/deps/aggregator.py +67 -0
- apm_cli/deps/verifier.py +102 -0
- apm_cli/factory.py +59 -0
- apm_cli/primitives/__init__.py +16 -0
- apm_cli/primitives/discovery.py +142 -0
- apm_cli/primitives/models.py +115 -0
- apm_cli/primitives/parser.py +197 -0
- apm_cli/registry/__init__.py +6 -0
- apm_cli/registry/client.py +156 -0
- apm_cli/registry/integration.py +154 -0
- apm_cli/runtime/__init__.py +9 -0
- apm_cli/runtime/base.py +63 -0
- apm_cli/runtime/codex_runtime.py +149 -0
- apm_cli/runtime/factory.py +130 -0
- apm_cli/runtime/llm_runtime.py +155 -0
- apm_cli/runtime/manager.py +226 -0
- apm_cli/utils/__init__.py +1 -0
- apm_cli/utils/helpers.py +101 -0
- apm_cli/version.py +54 -0
- apm_cli/workflow/__init__.py +1 -0
- apm_cli/workflow/discovery.py +100 -0
- apm_cli/workflow/parser.py +92 -0
- apm_cli/workflow/runner.py +193 -0
- apm_cli-0.1.0.dist-info/METADATA +407 -0
- apm_cli-0.1.0.dist-info/RECORD +48 -0
- apm_cli-0.1.0.dist-info/WHEEL +5 -0
- apm_cli-0.1.0.dist-info/entry_points.txt +2 -0
- apm_cli-0.1.0.dist-info/licenses/AUTHORS +13 -0
- apm_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- apm_cli-0.1.0.dist-info/top_level.txt +1 -0
apm_cli/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Adapters package."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Client adapters package."""
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""Base adapter interface for MCP clients."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MCPClientAdapter(ABC):
|
|
7
|
+
"""Base adapter for MCP clients."""
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def get_config_path(self):
|
|
11
|
+
"""Get the path to the MCP configuration file."""
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def update_config(self, config_updates):
|
|
16
|
+
"""Update the MCP configuration."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def get_current_config(self):
|
|
21
|
+
"""Get the current MCP configuration."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def configure_mcp_server(self, server_url, server_name=None, enabled=True):
|
|
26
|
+
"""Configure an MCP server in the client configuration.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
server_url (str): URL of the MCP server.
|
|
30
|
+
server_name (str, optional): Name of the server. Defaults to None.
|
|
31
|
+
enabled (bool, optional): Whether to enable the server. Defaults to True.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
bool: True if successful, False otherwise.
|
|
35
|
+
"""
|
|
36
|
+
pass
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"""VSCode implementation of MCP client adapter.
|
|
2
|
+
|
|
3
|
+
This adapter implements the VSCode-specific handling of MCP server configuration,
|
|
4
|
+
following the official documentation at:
|
|
5
|
+
https://code.visualstudio.com/docs/copilot/chat/mcp-servers
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from .base import MCPClientAdapter
|
|
12
|
+
from ...registry.client import SimpleRegistryClient
|
|
13
|
+
from ...registry.integration import RegistryIntegration
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class VSCodeClientAdapter(MCPClientAdapter):
|
|
17
|
+
"""VSCode implementation of MCP client adapter.
|
|
18
|
+
|
|
19
|
+
This adapter handles VSCode-specific configuration for MCP servers using
|
|
20
|
+
a repository-level .vscode/mcp.json file, following the format specified
|
|
21
|
+
in the VSCode documentation.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, registry_url=None):
|
|
25
|
+
"""Initialize the VSCode client adapter.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
registry_url (str, optional): URL of the MCP registry.
|
|
29
|
+
If not provided, uses the MCP_REGISTRY_URL environment variable
|
|
30
|
+
or falls back to the default demo registry.
|
|
31
|
+
"""
|
|
32
|
+
self.registry_client = SimpleRegistryClient(registry_url)
|
|
33
|
+
self.registry_integration = RegistryIntegration(registry_url)
|
|
34
|
+
|
|
35
|
+
def get_config_path(self):
|
|
36
|
+
"""Get the path to the VSCode MCP configuration file in the repository.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
str: Path to the .vscode/mcp.json file.
|
|
40
|
+
"""
|
|
41
|
+
# Use the current working directory as the repository root
|
|
42
|
+
repo_root = Path(os.getcwd())
|
|
43
|
+
|
|
44
|
+
# Path to .vscode/mcp.json in the repository
|
|
45
|
+
vscode_dir = repo_root / ".vscode"
|
|
46
|
+
mcp_config_path = vscode_dir / "mcp.json"
|
|
47
|
+
|
|
48
|
+
# Create the .vscode directory if it doesn't exist
|
|
49
|
+
try:
|
|
50
|
+
if not vscode_dir.exists():
|
|
51
|
+
vscode_dir.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(f"Warning: Could not create .vscode directory: {e}")
|
|
54
|
+
|
|
55
|
+
return str(mcp_config_path)
|
|
56
|
+
|
|
57
|
+
def update_config(self, config_updates):
|
|
58
|
+
"""Update the VSCode MCP configuration with new values.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
config_updates (dict): Dictionary of settings to update.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
bool: True if successful, False otherwise.
|
|
65
|
+
"""
|
|
66
|
+
config_path = self.get_config_path()
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
# Read existing config or create a new one
|
|
70
|
+
try:
|
|
71
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
72
|
+
config = json.load(f)
|
|
73
|
+
except (FileNotFoundError, json.JSONDecodeError):
|
|
74
|
+
config = {}
|
|
75
|
+
|
|
76
|
+
# Update config with new values or remove entries set to None
|
|
77
|
+
for key, value in config_updates.items():
|
|
78
|
+
if value is None:
|
|
79
|
+
# Remove the entry if it exists
|
|
80
|
+
if key in config:
|
|
81
|
+
del config[key]
|
|
82
|
+
else:
|
|
83
|
+
config[key] = value
|
|
84
|
+
|
|
85
|
+
# Write the updated config
|
|
86
|
+
with open(config_path, "w", encoding="utf-8") as f:
|
|
87
|
+
json.dump(config, f, indent=2)
|
|
88
|
+
|
|
89
|
+
return True
|
|
90
|
+
except Exception as e:
|
|
91
|
+
print(f"Error updating VSCode MCP configuration: {e}")
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
def get_current_config(self):
|
|
95
|
+
"""Get the current VSCode MCP configuration.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
dict: Current VSCode MCP configuration from the local .vscode/mcp.json file.
|
|
99
|
+
"""
|
|
100
|
+
config_path = self.get_config_path()
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
try:
|
|
104
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
105
|
+
return json.load(f)
|
|
106
|
+
except (FileNotFoundError, json.JSONDecodeError):
|
|
107
|
+
return {}
|
|
108
|
+
except Exception as e:
|
|
109
|
+
print(f"Error reading VSCode MCP configuration: {e}")
|
|
110
|
+
return {}
|
|
111
|
+
|
|
112
|
+
def configure_mcp_server(self, server_url, server_name=None, enabled=True):
|
|
113
|
+
"""Configure an MCP server in VSCode configuration.
|
|
114
|
+
|
|
115
|
+
This method follows the VSCode documentation for MCP server configuration format:
|
|
116
|
+
https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_configuration-format
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
server_url (str): URL or identifier of the MCP server.
|
|
120
|
+
server_name (str, optional): Name of the server. Defaults to None.
|
|
121
|
+
enabled (bool, optional): Ignored parameter, kept for API compatibility.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
bool: True if successful, False otherwise.
|
|
125
|
+
"""
|
|
126
|
+
if not server_url:
|
|
127
|
+
print("Error: server_url cannot be empty")
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
if not server_name:
|
|
131
|
+
server_name = server_url
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
# Use enhanced lookup with multiple strategies
|
|
135
|
+
server_info = self.registry_client.find_server_by_reference(server_url)
|
|
136
|
+
|
|
137
|
+
# Fail if server is not found in registry - security requirement
|
|
138
|
+
if not server_info:
|
|
139
|
+
raise ValueError(f"Failed to retrieve server details for '{server_url}'. Server not found in registry.")
|
|
140
|
+
|
|
141
|
+
# Format server configuration and get input variables if any
|
|
142
|
+
server_config, input_vars = self._format_server_config(server_info)
|
|
143
|
+
|
|
144
|
+
config = self.get_current_config()
|
|
145
|
+
|
|
146
|
+
# Make sure we have the servers object
|
|
147
|
+
if "servers" not in config:
|
|
148
|
+
config["servers"] = {}
|
|
149
|
+
|
|
150
|
+
# Add input variables if any
|
|
151
|
+
if input_vars:
|
|
152
|
+
if "inputs" not in config:
|
|
153
|
+
config["inputs"] = []
|
|
154
|
+
# Merge with existing inputs, avoiding duplicates by id
|
|
155
|
+
existing_input_ids = [input_var.get("id") for input_var in config.get("inputs", [])]
|
|
156
|
+
for input_var in input_vars:
|
|
157
|
+
if input_var.get("id") not in existing_input_ids:
|
|
158
|
+
config["inputs"].append(input_var)
|
|
159
|
+
|
|
160
|
+
# Add the server configuration
|
|
161
|
+
config["servers"][server_name] = server_config
|
|
162
|
+
|
|
163
|
+
# Update the configuration
|
|
164
|
+
return self.update_config(config)
|
|
165
|
+
|
|
166
|
+
except ValueError as ve:
|
|
167
|
+
# Re-raise ValueError to indicate missing server details
|
|
168
|
+
raise ve
|
|
169
|
+
except Exception as e:
|
|
170
|
+
print(f"Error configuring MCP server: {e}")
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
def _format_server_config(self, server_info):
|
|
174
|
+
"""Format server details into VSCode mcp.json compatible format.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
server_info (dict): Server information from registry.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
tuple: (server_config, input_vars) where:
|
|
181
|
+
- server_config is the formatted server configuration for mcp.json
|
|
182
|
+
- input_vars is a list of input variable definitions
|
|
183
|
+
"""
|
|
184
|
+
# Initialize the base config structure
|
|
185
|
+
server_config = {}
|
|
186
|
+
input_vars = []
|
|
187
|
+
|
|
188
|
+
# Check for packages information
|
|
189
|
+
if "packages" in server_info and server_info["packages"]:
|
|
190
|
+
package = server_info["packages"][0]
|
|
191
|
+
runtime_hint = package.get("runtime_hint", "")
|
|
192
|
+
|
|
193
|
+
# Handle npm packages
|
|
194
|
+
if runtime_hint == "npx" or "npm" in package.get("registry_name", "").lower():
|
|
195
|
+
# Get args directly from runtime_arguments
|
|
196
|
+
args = []
|
|
197
|
+
if "runtime_arguments" in package and package["runtime_arguments"]:
|
|
198
|
+
for arg in package["runtime_arguments"]:
|
|
199
|
+
if arg.get("is_required", False) and arg.get("value_hint"):
|
|
200
|
+
args.append(arg.get("value_hint"))
|
|
201
|
+
|
|
202
|
+
# Fallback if no runtime_arguments are provided
|
|
203
|
+
if not args and package.get("name"):
|
|
204
|
+
args = [package.get("name")]
|
|
205
|
+
|
|
206
|
+
server_config = {
|
|
207
|
+
"type": "stdio",
|
|
208
|
+
"command": "npx",
|
|
209
|
+
"args": args
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# Handle docker packages
|
|
213
|
+
elif runtime_hint == "docker":
|
|
214
|
+
# Get args directly from runtime_arguments
|
|
215
|
+
args = []
|
|
216
|
+
if "runtime_arguments" in package and package["runtime_arguments"]:
|
|
217
|
+
for arg in package["runtime_arguments"]:
|
|
218
|
+
if arg.get("is_required", False) and arg.get("value_hint"):
|
|
219
|
+
args.append(arg.get("value_hint"))
|
|
220
|
+
|
|
221
|
+
# Fallback if no runtime_arguments are provided - use standard docker run command
|
|
222
|
+
if not args:
|
|
223
|
+
args = ["run", "-i", "--rm", package.get("name")]
|
|
224
|
+
|
|
225
|
+
server_config = {
|
|
226
|
+
"type": "stdio",
|
|
227
|
+
"command": "docker",
|
|
228
|
+
"args": args
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
# Handle Python packages
|
|
232
|
+
elif runtime_hint in ["uvx", "pip", "python"] or "python" in runtime_hint or package.get("registry_name", "").lower() == "pypi":
|
|
233
|
+
# Determine the command based on runtime_hint
|
|
234
|
+
if runtime_hint == "uvx":
|
|
235
|
+
command = "uvx"
|
|
236
|
+
elif "python" in runtime_hint:
|
|
237
|
+
# Use the specified Python path if it's a full path, otherwise default to python3
|
|
238
|
+
command = "python3" if runtime_hint in ["python", "pip"] else runtime_hint
|
|
239
|
+
else:
|
|
240
|
+
command = "python3"
|
|
241
|
+
|
|
242
|
+
# Get args directly from runtime_arguments
|
|
243
|
+
args = []
|
|
244
|
+
if "runtime_arguments" in package and package["runtime_arguments"]:
|
|
245
|
+
for arg in package["runtime_arguments"]:
|
|
246
|
+
if arg.get("is_required", False) and arg.get("value_hint"):
|
|
247
|
+
args.append(arg.get("value_hint"))
|
|
248
|
+
|
|
249
|
+
# Fallback if no runtime_arguments are provided
|
|
250
|
+
if not args:
|
|
251
|
+
if runtime_hint == "uvx":
|
|
252
|
+
module_name = package.get("name", "").replace("mcp-server-", "")
|
|
253
|
+
args = [f"mcp-server-{module_name}"]
|
|
254
|
+
else:
|
|
255
|
+
module_name = package.get("name", "").replace("mcp-server-", "").replace("-", "_")
|
|
256
|
+
args = ["-m", f"mcp_server_{module_name}"]
|
|
257
|
+
|
|
258
|
+
server_config = {
|
|
259
|
+
"type": "stdio",
|
|
260
|
+
"command": command,
|
|
261
|
+
"args": args
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# Add environment variables if present
|
|
265
|
+
if "environment_variables" in package and package["environment_variables"]:
|
|
266
|
+
server_config["env"] = {}
|
|
267
|
+
for env_var in package["environment_variables"]:
|
|
268
|
+
if "name" in env_var:
|
|
269
|
+
# Convert variable name to lowercase and replace underscores with hyphens for VS Code convention
|
|
270
|
+
input_var_name = env_var["name"].lower().replace("_", "-")
|
|
271
|
+
|
|
272
|
+
# Create the input variable reference
|
|
273
|
+
server_config["env"][env_var["name"]] = f"${{input:{input_var_name}}}"
|
|
274
|
+
|
|
275
|
+
# Create the input variable definition
|
|
276
|
+
input_var_def = {
|
|
277
|
+
"type": "promptString",
|
|
278
|
+
"id": input_var_name,
|
|
279
|
+
"description": env_var.get("description", f"{env_var['name']} for MCP server"),
|
|
280
|
+
"password": True # Default to True for security
|
|
281
|
+
}
|
|
282
|
+
input_vars.append(input_var_def)
|
|
283
|
+
|
|
284
|
+
# If no server config was created from packages, check for other server types
|
|
285
|
+
if not server_config:
|
|
286
|
+
# Check for SSE endpoints
|
|
287
|
+
if "sse_endpoint" in server_info:
|
|
288
|
+
server_config = {
|
|
289
|
+
"type": "sse",
|
|
290
|
+
"url": server_info["sse_endpoint"],
|
|
291
|
+
"headers": server_info.get("sse_headers", {})
|
|
292
|
+
}
|
|
293
|
+
# Default fallback
|
|
294
|
+
else:
|
|
295
|
+
server_config = {
|
|
296
|
+
"type": "stdio",
|
|
297
|
+
"command": "uvx",
|
|
298
|
+
"args": [f"mcp-server-{server_info.get('name', '')}"]
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return server_config, input_vars
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Package manager adapters package."""
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Base adapter interface for MCP package managers."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MCPPackageManagerAdapter(ABC):
|
|
7
|
+
"""Base adapter for MCP package managers."""
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
def install(self, package_name, version=None):
|
|
11
|
+
"""Install an MCP package."""
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def uninstall(self, package_name):
|
|
16
|
+
"""Uninstall an MCP package."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def list_installed(self):
|
|
21
|
+
"""List all installed MCP packages."""
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def search(self, query):
|
|
26
|
+
"""Search for MCP packages."""
|
|
27
|
+
pass
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Implementation of the default MCP package manager."""
|
|
2
|
+
|
|
3
|
+
from .base import MCPPackageManagerAdapter
|
|
4
|
+
from ...config import get_default_client
|
|
5
|
+
from ...registry.integration import RegistryIntegration
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DefaultMCPPackageManager(MCPPackageManagerAdapter):
|
|
9
|
+
"""Implementation of the default MCP package manager."""
|
|
10
|
+
|
|
11
|
+
def install(self, package_name, version=None):
|
|
12
|
+
"""Install an MCP package.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
package_name (str): Name of the package to install.
|
|
16
|
+
version (str, optional): Version of the package to install.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
bool: True if successful, False otherwise.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
# Import here to avoid circular import
|
|
24
|
+
from ...factory import ClientFactory
|
|
25
|
+
|
|
26
|
+
client_type = get_default_client()
|
|
27
|
+
client_adapter = ClientFactory.create_client(client_type)
|
|
28
|
+
|
|
29
|
+
# For VSCode, configure MCP server in mcp.json
|
|
30
|
+
result = client_adapter.configure_mcp_server(package_name, package_name, True)
|
|
31
|
+
|
|
32
|
+
if result:
|
|
33
|
+
print(f"Successfully installed {package_name}")
|
|
34
|
+
return result
|
|
35
|
+
except Exception as e:
|
|
36
|
+
print(f"Error installing package {package_name}: {e}")
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
def uninstall(self, package_name):
|
|
40
|
+
"""Uninstall an MCP package.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
package_name (str): Name of the package to uninstall.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
bool: True if successful, False otherwise.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
# Import here to avoid circular import
|
|
51
|
+
from ...factory import ClientFactory
|
|
52
|
+
|
|
53
|
+
client_type = get_default_client()
|
|
54
|
+
client_adapter = ClientFactory.create_client(client_type)
|
|
55
|
+
config = client_adapter.get_current_config()
|
|
56
|
+
|
|
57
|
+
# For VSCode, remove the server from mcp.json
|
|
58
|
+
if "servers" in config and package_name in config["servers"]:
|
|
59
|
+
servers = config["servers"]
|
|
60
|
+
servers.pop(package_name, None)
|
|
61
|
+
result = client_adapter.update_config({"servers": servers})
|
|
62
|
+
|
|
63
|
+
if result:
|
|
64
|
+
print(f"Successfully uninstalled {package_name}")
|
|
65
|
+
return result
|
|
66
|
+
else:
|
|
67
|
+
print(f"Package {package_name} not found in configuration")
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
except Exception as e:
|
|
71
|
+
print(f"Error uninstalling package {package_name}: {e}")
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
def list_installed(self):
|
|
75
|
+
"""List all installed MCP packages.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
list: List of installed packages.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
# Import here to avoid circular import
|
|
83
|
+
from ...factory import ClientFactory
|
|
84
|
+
|
|
85
|
+
# Get client type from configuration (default is vscode)
|
|
86
|
+
client_type = get_default_client()
|
|
87
|
+
|
|
88
|
+
# Create client adapter
|
|
89
|
+
client_adapter = ClientFactory.create_client(client_type)
|
|
90
|
+
|
|
91
|
+
# Get config from local .vscode/mcp.json file
|
|
92
|
+
config = client_adapter.get_current_config()
|
|
93
|
+
|
|
94
|
+
# Extract server names from the config
|
|
95
|
+
servers = config.get("servers", {})
|
|
96
|
+
|
|
97
|
+
# Return the list of server names
|
|
98
|
+
return list(servers.keys())
|
|
99
|
+
except Exception as e:
|
|
100
|
+
print(f"Error retrieving installed MCP servers: {e}")
|
|
101
|
+
return []
|
|
102
|
+
|
|
103
|
+
def search(self, query):
|
|
104
|
+
"""Search for MCP packages.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
query (str): Search query.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
list: List of packages matching the query.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
# Use the registry integration to search for packages
|
|
115
|
+
registry = RegistryIntegration()
|
|
116
|
+
packages = registry.search_packages(query)
|
|
117
|
+
|
|
118
|
+
# Return the list of package IDs/names
|
|
119
|
+
return [pkg.get("id", pkg.get("name", "Unknown")) for pkg in packages] if packages else []
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
print(f"Error searching for packages: {e}")
|
|
123
|
+
return []
|