mcp-proxy-adapter 4.1.1__py3-none-any.whl → 6.0.1__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.
- mcp_proxy_adapter/__main__.py +32 -0
- mcp_proxy_adapter/api/app.py +290 -33
- mcp_proxy_adapter/api/handlers.py +32 -6
- mcp_proxy_adapter/api/middleware/__init__.py +38 -32
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
- mcp_proxy_adapter/api/middleware/factory.py +243 -0
- mcp_proxy_adapter/api/middleware/logging.py +32 -6
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +201 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
- mcp_proxy_adapter/commands/__init__.py +19 -4
- mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
- mcp_proxy_adapter/commands/base.py +66 -32
- mcp_proxy_adapter/commands/builtin_commands.py +95 -0
- mcp_proxy_adapter/commands/catalog_manager.py +838 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
- mcp_proxy_adapter/commands/command_registry.py +711 -354
- mcp_proxy_adapter/commands/dependency_manager.py +245 -0
- mcp_proxy_adapter/commands/echo_command.py +81 -0
- mcp_proxy_adapter/commands/health_command.py +8 -1
- mcp_proxy_adapter/commands/help_command.py +21 -14
- mcp_proxy_adapter/commands/hooks.py +200 -167
- mcp_proxy_adapter/commands/key_management_command.py +506 -0
- mcp_proxy_adapter/commands/load_command.py +176 -0
- mcp_proxy_adapter/commands/plugins_command.py +235 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +409 -0
- mcp_proxy_adapter/commands/reload_command.py +48 -50
- mcp_proxy_adapter/commands/result.py +1 -0
- mcp_proxy_adapter/commands/role_test_command.py +141 -0
- mcp_proxy_adapter/commands/roles_management_command.py +697 -0
- mcp_proxy_adapter/commands/security_command.py +488 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +366 -0
- mcp_proxy_adapter/commands/token_management_command.py +529 -0
- mcp_proxy_adapter/commands/transport_management_command.py +144 -0
- mcp_proxy_adapter/commands/unload_command.py +158 -0
- mcp_proxy_adapter/config.py +394 -14
- mcp_proxy_adapter/core/app_factory.py +410 -0
- mcp_proxy_adapter/core/app_runner.py +272 -0
- mcp_proxy_adapter/core/auth_validator.py +606 -0
- mcp_proxy_adapter/core/certificate_utils.py +1045 -0
- mcp_proxy_adapter/core/client.py +574 -0
- mcp_proxy_adapter/core/client_manager.py +284 -0
- mcp_proxy_adapter/core/client_security.py +384 -0
- mcp_proxy_adapter/core/config_converter.py +405 -0
- mcp_proxy_adapter/core/config_validator.py +218 -0
- mcp_proxy_adapter/core/logging.py +19 -3
- mcp_proxy_adapter/core/mtls_asgi.py +156 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/protocol_manager.py +385 -0
- mcp_proxy_adapter/core/proxy_client.py +602 -0
- mcp_proxy_adapter/core/proxy_registration.py +522 -0
- mcp_proxy_adapter/core/role_utils.py +426 -0
- mcp_proxy_adapter/core/security_adapter.py +370 -0
- mcp_proxy_adapter/core/security_factory.py +239 -0
- mcp_proxy_adapter/core/security_integration.py +286 -0
- mcp_proxy_adapter/core/server_adapter.py +282 -0
- mcp_proxy_adapter/core/server_engine.py +270 -0
- mcp_proxy_adapter/core/settings.py +1 -0
- mcp_proxy_adapter/core/ssl_utils.py +234 -0
- mcp_proxy_adapter/core/transport_manager.py +292 -0
- mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
- mcp_proxy_adapter/custom_openapi.py +22 -11
- mcp_proxy_adapter/examples/__init__.py +13 -4
- mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
- mcp_proxy_adapter/examples/debug_request_state.py +112 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
- mcp_proxy_adapter/examples/demo_client.py +275 -0
- mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
- mcp_proxy_adapter/examples/full_application/main.py +173 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
- mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
- mcp_proxy_adapter/examples/generate_certificates.py +177 -0
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
- mcp_proxy_adapter/examples/run_example.py +59 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
- mcp_proxy_adapter/examples/run_security_tests.py +544 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
- mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
- mcp_proxy_adapter/examples/security_test_client.py +782 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
- mcp_proxy_adapter/examples/test_config.py +148 -0
- mcp_proxy_adapter/examples/test_config_generator.py +86 -0
- mcp_proxy_adapter/examples/test_examples.py +281 -0
- mcp_proxy_adapter/examples/universal_client.py +620 -0
- mcp_proxy_adapter/main.py +93 -0
- mcp_proxy_adapter/utils/config_generator.py +1008 -0
- mcp_proxy_adapter/version.py +5 -2
- mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
- mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
- mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
- mcp_proxy_adapter/api/middleware/auth.py +0 -146
- mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
- mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
- mcp_proxy_adapter/examples/README.md +0 -124
- mcp_proxy_adapter/examples/basic_server/README.md +0 -60
- mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
- mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
- mcp_proxy_adapter/examples/basic_server/config.json +0 -35
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
- mcp_proxy_adapter/examples/basic_server/server.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
- mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -250
- mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
- mcp_proxy_adapter/examples/custom_commands/config.json +0 -35
- mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
- mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
- mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
- mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
- mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
- mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
- mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
- mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
- mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
- mcp_proxy_adapter/examples/custom_commands/server.py +0 -228
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
- mcp_proxy_adapter/examples/deployment/README.md +0 -49
- mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
- mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
- mcp_proxy_adapter/examples/deployment/config.json +0 -29
- mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
- mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
- mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
- mcp_proxy_adapter/examples/deployment/run.sh +0 -43
- mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
- mcp_proxy_adapter/schemas/base_schema.json +0 -114
- mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
- mcp_proxy_adapter/tests/__init__.py +0 -0
- mcp_proxy_adapter/tests/api/__init__.py +0 -3
- mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
- mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
- mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
- mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
- mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
- mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
- mcp_proxy_adapter/tests/commands/__init__.py +0 -3
- mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
- mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
- mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
- mcp_proxy_adapter/tests/conftest.py +0 -131
- mcp_proxy_adapter/tests/functional/__init__.py +0 -3
- mcp_proxy_adapter/tests/functional/test_api.py +0 -253
- mcp_proxy_adapter/tests/integration/__init__.py +0 -3
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
- mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
- mcp_proxy_adapter/tests/performance/__init__.py +0 -3
- mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
- mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
- mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
- mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
- mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
- mcp_proxy_adapter/tests/test_base_command.py +0 -123
- mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
- mcp_proxy_adapter/tests/test_command_registry.py +0 -281
- mcp_proxy_adapter/tests/test_config.py +0 -127
- mcp_proxy_adapter/tests/test_utils.py +0 -65
- mcp_proxy_adapter/tests/unit/__init__.py +0 -3
- mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
- mcp_proxy_adapter/tests/unit/test_config.py +0 -217
- mcp_proxy_adapter-4.1.1.dist-info/METADATA +0 -200
- mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,245 @@
|
|
1
|
+
"""
|
2
|
+
Dependency management system for remote plugins.
|
3
|
+
|
4
|
+
This module handles automatic installation and verification of plugin dependencies
|
5
|
+
using pip and other package management tools.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import subprocess
|
9
|
+
import sys
|
10
|
+
import importlib
|
11
|
+
import pkg_resources
|
12
|
+
from typing import List, Dict, Any, Optional, Tuple
|
13
|
+
from pathlib import Path
|
14
|
+
|
15
|
+
from mcp_proxy_adapter.core.logging import logger
|
16
|
+
|
17
|
+
|
18
|
+
class DependencyManager:
|
19
|
+
"""
|
20
|
+
Manages plugin dependencies installation and verification.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def __init__(self):
|
24
|
+
"""Initialize dependency manager."""
|
25
|
+
self._installed_packages: Dict[str, str] = {}
|
26
|
+
self._load_installed_packages()
|
27
|
+
|
28
|
+
def _load_installed_packages(self) -> None:
|
29
|
+
"""Load list of currently installed packages."""
|
30
|
+
try:
|
31
|
+
installed = pkg_resources.working_set
|
32
|
+
for dist in installed:
|
33
|
+
self._installed_packages[dist.project_name.lower()] = dist.version
|
34
|
+
except Exception as e:
|
35
|
+
logger.warning(f"Failed to load installed packages: {e}")
|
36
|
+
|
37
|
+
def check_dependencies(self, dependencies: List[str]) -> Tuple[bool, List[str], List[str]]:
|
38
|
+
"""
|
39
|
+
Check if dependencies are satisfied.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
dependencies: List of dependency names
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
Tuple of (all_satisfied, missing_deps, installed_deps)
|
46
|
+
"""
|
47
|
+
if not dependencies:
|
48
|
+
return True, [], []
|
49
|
+
|
50
|
+
missing_deps = []
|
51
|
+
installed_deps = []
|
52
|
+
|
53
|
+
for dep in dependencies:
|
54
|
+
if self._is_dependency_satisfied(dep):
|
55
|
+
installed_deps.append(dep)
|
56
|
+
else:
|
57
|
+
missing_deps.append(dep)
|
58
|
+
|
59
|
+
all_satisfied = len(missing_deps) == 0
|
60
|
+
return all_satisfied, missing_deps, installed_deps
|
61
|
+
|
62
|
+
def _is_dependency_satisfied(self, dependency: str) -> bool:
|
63
|
+
"""
|
64
|
+
Check if a single dependency is satisfied.
|
65
|
+
|
66
|
+
Args:
|
67
|
+
dependency: Dependency name or spec
|
68
|
+
|
69
|
+
Returns:
|
70
|
+
True if dependency is satisfied, False otherwise
|
71
|
+
"""
|
72
|
+
# Try to import the module
|
73
|
+
try:
|
74
|
+
importlib.import_module(dependency)
|
75
|
+
return True
|
76
|
+
except ImportError:
|
77
|
+
pass
|
78
|
+
|
79
|
+
# Check if it's installed as a package
|
80
|
+
try:
|
81
|
+
pkg_resources.require(dependency)
|
82
|
+
return True
|
83
|
+
except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict):
|
84
|
+
pass
|
85
|
+
|
86
|
+
# Check installed packages cache
|
87
|
+
dep_name = dependency.split('==')[0].split('>=')[0].split('<=')[0].split('!=')[0].split('~=')[0]
|
88
|
+
if dep_name.lower() in self._installed_packages:
|
89
|
+
return True
|
90
|
+
|
91
|
+
return False
|
92
|
+
|
93
|
+
def install_dependencies(self, dependencies: List[str], user_install: bool = False) -> Tuple[bool, List[str], List[str]]:
|
94
|
+
"""
|
95
|
+
Install dependencies using pip.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
dependencies: List of dependency names to install
|
99
|
+
user_install: Whether to install for current user only
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
Tuple of (success, installed_deps, failed_deps)
|
103
|
+
"""
|
104
|
+
if not dependencies:
|
105
|
+
return True, [], []
|
106
|
+
|
107
|
+
installed_deps = []
|
108
|
+
failed_deps = []
|
109
|
+
|
110
|
+
for dep in dependencies:
|
111
|
+
try:
|
112
|
+
if self._install_single_dependency(dep, user_install):
|
113
|
+
installed_deps.append(dep)
|
114
|
+
logger.info(f"Successfully installed dependency: {dep}")
|
115
|
+
else:
|
116
|
+
failed_deps.append(dep)
|
117
|
+
logger.error(f"Failed to install dependency: {dep}")
|
118
|
+
except Exception as e:
|
119
|
+
failed_deps.append(dep)
|
120
|
+
logger.error(f"Error installing dependency {dep}: {e}")
|
121
|
+
|
122
|
+
success = len(failed_deps) == 0
|
123
|
+
|
124
|
+
# Reload installed packages cache
|
125
|
+
if success:
|
126
|
+
self._load_installed_packages()
|
127
|
+
|
128
|
+
return success, installed_deps, failed_deps
|
129
|
+
|
130
|
+
def _install_single_dependency(self, dependency: str, user_install: bool = False) -> bool:
|
131
|
+
"""
|
132
|
+
Install a single dependency using pip.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
dependency: Dependency name or spec
|
136
|
+
user_install: Whether to install for current user only
|
137
|
+
|
138
|
+
Returns:
|
139
|
+
True if installation successful, False otherwise
|
140
|
+
"""
|
141
|
+
try:
|
142
|
+
# Build pip command
|
143
|
+
cmd = [sys.executable, "-m", "pip", "install"]
|
144
|
+
|
145
|
+
if user_install:
|
146
|
+
cmd.append("--user")
|
147
|
+
|
148
|
+
# Add quiet flag to reduce output
|
149
|
+
cmd.append("--quiet")
|
150
|
+
|
151
|
+
# Add dependency
|
152
|
+
cmd.append(dependency)
|
153
|
+
|
154
|
+
logger.debug(f"Installing dependency: {' '.join(cmd)}")
|
155
|
+
|
156
|
+
# Run pip install
|
157
|
+
result = subprocess.run(
|
158
|
+
cmd,
|
159
|
+
capture_output=True,
|
160
|
+
text=True,
|
161
|
+
timeout=300 # 5 minutes timeout
|
162
|
+
)
|
163
|
+
|
164
|
+
if result.returncode == 0:
|
165
|
+
logger.debug(f"Successfully installed {dependency}")
|
166
|
+
return True
|
167
|
+
else:
|
168
|
+
logger.error(f"Failed to install {dependency}: {result.stderr}")
|
169
|
+
return False
|
170
|
+
|
171
|
+
except subprocess.TimeoutExpired:
|
172
|
+
logger.error(f"Timeout while installing {dependency}")
|
173
|
+
return False
|
174
|
+
except Exception as e:
|
175
|
+
logger.error(f"Error installing {dependency}: {e}")
|
176
|
+
return False
|
177
|
+
|
178
|
+
def verify_installation(self, dependencies: List[str]) -> Tuple[bool, List[str]]:
|
179
|
+
"""
|
180
|
+
Verify that dependencies are properly installed.
|
181
|
+
|
182
|
+
Args:
|
183
|
+
dependencies: List of dependencies to verify
|
184
|
+
|
185
|
+
Returns:
|
186
|
+
Tuple of (all_verified, failed_verifications)
|
187
|
+
"""
|
188
|
+
if not dependencies:
|
189
|
+
return True, []
|
190
|
+
|
191
|
+
failed_verifications = []
|
192
|
+
|
193
|
+
for dep in dependencies:
|
194
|
+
if not self._is_dependency_satisfied(dep):
|
195
|
+
failed_verifications.append(dep)
|
196
|
+
|
197
|
+
all_verified = len(failed_verifications) == 0
|
198
|
+
return all_verified, failed_verifications
|
199
|
+
|
200
|
+
def get_dependency_info(self, dependency: str) -> Dict[str, Any]:
|
201
|
+
"""
|
202
|
+
Get information about a dependency.
|
203
|
+
|
204
|
+
Args:
|
205
|
+
dependency: Dependency name
|
206
|
+
|
207
|
+
Returns:
|
208
|
+
Dictionary with dependency information
|
209
|
+
"""
|
210
|
+
info = {
|
211
|
+
"name": dependency,
|
212
|
+
"installed": False,
|
213
|
+
"version": None,
|
214
|
+
"importable": False
|
215
|
+
}
|
216
|
+
|
217
|
+
# Check if it's installed
|
218
|
+
try:
|
219
|
+
dist = pkg_resources.get_distribution(dependency)
|
220
|
+
info["installed"] = True
|
221
|
+
info["version"] = dist.version
|
222
|
+
except pkg_resources.DistributionNotFound:
|
223
|
+
pass
|
224
|
+
|
225
|
+
# Check if it's importable
|
226
|
+
try:
|
227
|
+
importlib.import_module(dependency)
|
228
|
+
info["importable"] = True
|
229
|
+
except ImportError:
|
230
|
+
pass
|
231
|
+
|
232
|
+
return info
|
233
|
+
|
234
|
+
def list_installed_dependencies(self) -> Dict[str, str]:
|
235
|
+
"""
|
236
|
+
Get list of all installed packages.
|
237
|
+
|
238
|
+
Returns:
|
239
|
+
Dictionary mapping package names to versions
|
240
|
+
"""
|
241
|
+
return self._installed_packages.copy()
|
242
|
+
|
243
|
+
|
244
|
+
# Global instance
|
245
|
+
dependency_manager = DependencyManager()
|
@@ -0,0 +1,81 @@
|
|
1
|
+
"""
|
2
|
+
Author: Vasiliy Zdanovskiy
|
3
|
+
email: vasilyvz@gmail.com
|
4
|
+
|
5
|
+
Echo command for testing purposes.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
from typing import Any, Dict, Optional
|
10
|
+
|
11
|
+
from mcp_proxy_adapter.commands.base import Command
|
12
|
+
from mcp_proxy_adapter.commands.result import SuccessResult
|
13
|
+
|
14
|
+
|
15
|
+
class EchoCommandResult(SuccessResult):
|
16
|
+
"""Result for echo command."""
|
17
|
+
|
18
|
+
def __init__(self, message: str, timestamp: Optional[str] = None):
|
19
|
+
data = {"message": message}
|
20
|
+
if timestamp:
|
21
|
+
data["timestamp"] = timestamp
|
22
|
+
super().__init__(data=data, message=message)
|
23
|
+
|
24
|
+
@classmethod
|
25
|
+
def get_schema(cls) -> Dict[str, Any]:
|
26
|
+
"""Get JSON schema for result."""
|
27
|
+
return {
|
28
|
+
"type": "object",
|
29
|
+
"properties": {
|
30
|
+
"success": {"type": "boolean"},
|
31
|
+
"data": {
|
32
|
+
"type": "object",
|
33
|
+
"properties": {
|
34
|
+
"message": {"type": "string"},
|
35
|
+
"timestamp": {"type": "string", "nullable": True}
|
36
|
+
}
|
37
|
+
},
|
38
|
+
"message": {"type": "string"}
|
39
|
+
},
|
40
|
+
"required": ["success", "data"]
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
class EchoCommand(Command):
|
45
|
+
"""Echo command for testing purposes."""
|
46
|
+
|
47
|
+
name = "echo"
|
48
|
+
version = "1.0.0"
|
49
|
+
descr = "Echo command for testing"
|
50
|
+
category = "testing"
|
51
|
+
author = "Vasiliy Zdanovskiy"
|
52
|
+
email = "vasilyvz@gmail.com"
|
53
|
+
result_class = EchoCommandResult
|
54
|
+
|
55
|
+
async def execute(self, **kwargs) -> EchoCommandResult:
|
56
|
+
"""Execute echo command."""
|
57
|
+
message = kwargs.get("message", "Hello, World!")
|
58
|
+
timestamp = kwargs.get("timestamp")
|
59
|
+
|
60
|
+
# Simulate some processing time
|
61
|
+
await asyncio.sleep(0.001)
|
62
|
+
|
63
|
+
return EchoCommandResult(message=message, timestamp=timestamp)
|
64
|
+
|
65
|
+
def get_schema(self) -> Dict[str, Any]:
|
66
|
+
"""Get command schema."""
|
67
|
+
return {
|
68
|
+
"type": "object",
|
69
|
+
"properties": {
|
70
|
+
"message": {
|
71
|
+
"type": "string",
|
72
|
+
"description": "Message to echo",
|
73
|
+
"default": "Hello, World!"
|
74
|
+
},
|
75
|
+
"timestamp": {
|
76
|
+
"type": "string",
|
77
|
+
"description": "Optional timestamp",
|
78
|
+
"nullable": True
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
@@ -12,6 +12,7 @@ from typing import Dict, Any, Optional
|
|
12
12
|
from mcp_proxy_adapter.commands.base import Command
|
13
13
|
from mcp_proxy_adapter.commands.result import CommandResult, SuccessResult
|
14
14
|
from mcp_proxy_adapter.commands.command_registry import registry
|
15
|
+
from mcp_proxy_adapter.core.proxy_registration import get_proxy_registration_status
|
15
16
|
|
16
17
|
|
17
18
|
class HealthResult(SuccessResult):
|
@@ -79,7 +80,7 @@ class HealthCommand(Command):
|
|
79
80
|
name = "health"
|
80
81
|
result_class = HealthResult
|
81
82
|
|
82
|
-
async def execute(self) -> HealthResult:
|
83
|
+
async def execute(self, **kwargs) -> HealthResult:
|
83
84
|
"""
|
84
85
|
Execute health command.
|
85
86
|
|
@@ -117,6 +118,12 @@ class HealthCommand(Command):
|
|
117
118
|
},
|
118
119
|
"commands": {
|
119
120
|
"registered_count": len(registry.get_all_commands())
|
121
|
+
},
|
122
|
+
"proxy_registration": {
|
123
|
+
"enabled": get_proxy_registration_status().get("enabled", False),
|
124
|
+
"registered": get_proxy_registration_status().get("registered", False),
|
125
|
+
"server_key": get_proxy_registration_status().get("server_key"),
|
126
|
+
"proxy_url": get_proxy_registration_status().get("proxy_url")
|
120
127
|
}
|
121
128
|
}
|
122
129
|
)
|
@@ -46,13 +46,15 @@ class HelpResult(CommandResult):
|
|
46
46
|
if self.command_info is not None:
|
47
47
|
logger.debug(f"HelpResult.to_dict: returning command_info for {self.command_info.get('name', 'unknown')}")
|
48
48
|
# Делаем безопасное получение всех полей с дефолтными значениями
|
49
|
+
metadata = self.command_info.get("metadata", {})
|
50
|
+
schema = self.command_info.get("schema", {})
|
49
51
|
return {
|
50
52
|
"cmdname": self.command_info.get("name", "unknown"),
|
51
53
|
"info": {
|
52
|
-
"description":
|
53
|
-
"summary":
|
54
|
-
"params":
|
55
|
-
"examples":
|
54
|
+
"description": metadata.get("description", ""),
|
55
|
+
"summary": metadata.get("summary", ""),
|
56
|
+
"params": schema.get("properties", {}),
|
57
|
+
"examples": metadata.get("examples", [])
|
56
58
|
}
|
57
59
|
}
|
58
60
|
|
@@ -190,14 +192,16 @@ class HelpCommand(Command):
|
|
190
192
|
if cmdname is not None and cmdname != "":
|
191
193
|
logger.debug(f"Обработка запроса для конкретной команды: {cmdname}")
|
192
194
|
try:
|
193
|
-
# Get command
|
194
|
-
|
195
|
+
# Get command info from registry
|
196
|
+
command_info = registry.get_command_info(cmdname)
|
197
|
+
if command_info is None:
|
198
|
+
raise NotFoundError(f"Command '{cmdname}' not found")
|
195
199
|
logger.debug(f"Получены метаданные для команды {cmdname}")
|
196
|
-
return HelpResult(command_info=
|
200
|
+
return HelpResult(command_info=command_info)
|
197
201
|
except NotFoundError:
|
198
202
|
logger.warning(f"Команда '{cmdname}' не найдена")
|
199
203
|
# Получаем список всех команд
|
200
|
-
all_commands = list(registry.
|
204
|
+
all_commands = list(registry.get_all_commands().keys())
|
201
205
|
if all_commands:
|
202
206
|
example_cmd = all_commands[0]
|
203
207
|
example = {
|
@@ -218,9 +222,9 @@ class HelpCommand(Command):
|
|
218
222
|
# Otherwise, return information about all available commands
|
219
223
|
logger.debug("Обработка запроса для всех команд")
|
220
224
|
|
221
|
-
# Get
|
222
|
-
|
223
|
-
logger.debug(f"Получены метаданные для {len(
|
225
|
+
# Get info for all commands
|
226
|
+
all_commands_info = registry.get_all_commands_info()
|
227
|
+
logger.debug(f"Получены метаданные для {len(all_commands_info.get('commands', {}))} команд")
|
224
228
|
|
225
229
|
# Prepare response format with tool metadata
|
226
230
|
result = {
|
@@ -240,17 +244,20 @@ class HelpCommand(Command):
|
|
240
244
|
}
|
241
245
|
|
242
246
|
# Add brief information about commands
|
243
|
-
|
247
|
+
commands_data = all_commands_info.get("commands", {})
|
248
|
+
for name, command_info in commands_data.items():
|
244
249
|
try:
|
245
250
|
logger.debug(f"Обработка метаданных команды {name}")
|
246
251
|
# Безопасное получение параметров с проверкой на наличие ключей
|
252
|
+
metadata = command_info.get("metadata", {})
|
253
|
+
schema = command_info.get("schema", {})
|
247
254
|
result["commands"][name] = {
|
248
255
|
"summary": metadata.get("summary", ""),
|
249
|
-
"params_count": len(
|
256
|
+
"params_count": len(schema.get("properties", {}))
|
250
257
|
}
|
251
258
|
except Exception as e:
|
252
259
|
logger.error(f"Ошибка при обработке метаданных команды {name}: {e}")
|
253
|
-
logger.debug(f"Метаданные команды {name}: {
|
260
|
+
logger.debug(f"Метаданные команды {name}: {command_info}")
|
254
261
|
# Пропускаем проблемную команду
|
255
262
|
continue
|
256
263
|
|