mcp-proxy-adapter 6.9.28__py3-none-any.whl → 6.9.30__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.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +10 -0
- mcp_proxy_adapter/__main__.py +8 -21
- mcp_proxy_adapter/api/app.py +10 -913
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +243 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_manager.py +166 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +78 -199
- mcp_proxy_adapter/api/middleware/__init__.py +1 -44
- mcp_proxy_adapter/api/middleware/base.py +0 -42
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +0 -85
- mcp_proxy_adapter/api/middleware/error_handling.py +1 -127
- mcp_proxy_adapter/api/middleware/factory.py +0 -94
- mcp_proxy_adapter/api/middleware/logging.py +0 -112
- mcp_proxy_adapter/api/middleware/performance.py +0 -35
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +2 -98
- mcp_proxy_adapter/api/middleware/transport_middleware.py +0 -37
- mcp_proxy_adapter/api/middleware/unified_security.py +10 -10
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +0 -118
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +0 -61
- mcp_proxy_adapter/api/tool_integration.py +0 -117
- mcp_proxy_adapter/api/tools.py +0 -46
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +21 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +36 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +128 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +324 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client.py +406 -0
- mcp_proxy_adapter/client/proxy.py +45 -0
- mcp_proxy_adapter/commands/__init__.py +44 -28
- mcp_proxy_adapter/commands/auth_validation_command.py +7 -344
- mcp_proxy_adapter/commands/base.py +19 -43
- mcp_proxy_adapter/commands/builtin_commands.py +0 -75
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +58 -928
- mcp_proxy_adapter/commands/cert_monitor_command.py +0 -88
- mcp_proxy_adapter/commands/certificate_management_command.py +0 -45
- mcp_proxy_adapter/commands/command_registry.py +172 -904
- mcp_proxy_adapter/commands/config_command.py +0 -28
- mcp_proxy_adapter/commands/dependency_container.py +1 -70
- mcp_proxy_adapter/commands/dependency_manager.py +0 -128
- mcp_proxy_adapter/commands/echo_command.py +0 -34
- mcp_proxy_adapter/commands/health_command.py +0 -3
- mcp_proxy_adapter/commands/help_command.py +0 -159
- mcp_proxy_adapter/commands/hooks.py +0 -137
- mcp_proxy_adapter/commands/key_management_command.py +0 -25
- mcp_proxy_adapter/commands/load_command.py +7 -78
- mcp_proxy_adapter/commands/plugins_command.py +0 -16
- mcp_proxy_adapter/commands/protocol_management_command.py +0 -28
- mcp_proxy_adapter/commands/proxy_registration_command.py +0 -88
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +0 -43
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +0 -80
- mcp_proxy_adapter/commands/result.py +25 -77
- mcp_proxy_adapter/commands/role_test_command.py +0 -44
- mcp_proxy_adapter/commands/roles_management_command.py +0 -199
- mcp_proxy_adapter/commands/security_command.py +0 -30
- mcp_proxy_adapter/commands/settings_command.py +0 -68
- mcp_proxy_adapter/commands/ssl_setup_command.py +0 -42
- mcp_proxy_adapter/commands/token_management_command.py +0 -1
- mcp_proxy_adapter/commands/transport_management_command.py +0 -20
- mcp_proxy_adapter/commands/unload_command.py +0 -71
- mcp_proxy_adapter/config.py +15 -626
- mcp_proxy_adapter/core/__init__.py +5 -39
- mcp_proxy_adapter/core/app_factory.py +14 -36
- mcp_proxy_adapter/core/app_runner.py +0 -27
- mcp_proxy_adapter/core/auth_validator.py +1 -93
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +371 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +183 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +110 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +70 -0
- mcp_proxy_adapter/core/certificate_utils.py +64 -903
- mcp_proxy_adapter/core/client.py +10 -9
- mcp_proxy_adapter/core/client_manager.py +0 -19
- mcp_proxy_adapter/core/client_security.py +0 -2
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +195 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +112 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +50 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +96 -0
- mcp_proxy_adapter/core/config_converter.py +0 -186
- mcp_proxy_adapter/core/config_validator.py +96 -1238
- mcp_proxy_adapter/core/errors.py +7 -42
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +2 -22
- mcp_proxy_adapter/core/mtls_asgi.py +0 -20
- mcp_proxy_adapter/core/mtls_asgi_app.py +0 -12
- mcp_proxy_adapter/core/mtls_proxy.py +0 -80
- mcp_proxy_adapter/core/mtls_server.py +3 -173
- mcp_proxy_adapter/core/protocol_manager.py +1 -191
- mcp_proxy_adapter/core/proxy/__init__.py +22 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +27 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +137 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +60 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +0 -1
- mcp_proxy_adapter/core/proxy_registration.py +36 -913
- mcp_proxy_adapter/core/role_utils.py +0 -308
- mcp_proxy_adapter/core/security_adapter.py +1 -36
- mcp_proxy_adapter/core/security_factory.py +1 -150
- mcp_proxy_adapter/core/security_integration.py +0 -33
- mcp_proxy_adapter/core/server_adapter.py +1 -40
- mcp_proxy_adapter/core/server_engine.py +2 -173
- mcp_proxy_adapter/core/settings.py +0 -127
- mcp_proxy_adapter/core/signal_handler.py +0 -65
- mcp_proxy_adapter/core/ssl_utils.py +19 -137
- mcp_proxy_adapter/core/transport_manager.py +0 -151
- mcp_proxy_adapter/core/unified_config_adapter.py +1 -193
- mcp_proxy_adapter/core/utils.py +1 -182
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +211 -0
- mcp_proxy_adapter/core/validation/file_validator.py +73 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +191 -0
- mcp_proxy_adapter/core/validation/security_validator.py +58 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +33 -652
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +0 -23
- mcp_proxy_adapter/examples/check_config.py +0 -2
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/config_builder.py +13 -2
- mcp_proxy_adapter/examples/config_cli.py +0 -1
- mcp_proxy_adapter/examples/create_test_configs.py +0 -46
- mcp_proxy_adapter/examples/debug_request_state.py +0 -1
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -47
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -45
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +0 -7
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +0 -2
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -59
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -54
- mcp_proxy_adapter/examples/full_application/main.py +186 -150
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +0 -107
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +0 -24
- mcp_proxy_adapter/examples/full_application/test_server.py +0 -58
- mcp_proxy_adapter/examples/generate_config.py +65 -11
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +0 -2
- mcp_proxy_adapter/examples/run_full_test_suite.py +0 -29
- mcp_proxy_adapter/examples/run_proxy_server.py +31 -71
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -27
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +24 -1075
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +133 -1425
- mcp_proxy_adapter/examples/test_config.py +0 -3
- mcp_proxy_adapter/examples/test_config_builder.py +25 -405
- mcp_proxy_adapter/examples/test_examples.py +0 -1
- mcp_proxy_adapter/examples/test_framework_complete.py +0 -2
- mcp_proxy_adapter/examples/test_mcp_server.py +0 -1
- mcp_proxy_adapter/examples/test_protocol_examples.py +0 -1
- mcp_proxy_adapter/examples/universal_client.py +0 -6
- mcp_proxy_adapter/examples/update_config_certificates.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +0 -187
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +70 -62
- mcp_proxy_adapter/openapi.py +0 -22
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.9.30.dist-info/RECORD +235 -0
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/entry_points.txt +1 -1
- mcp_proxy_adapter-6.9.28.dist-info/RECORD +0 -149
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Main catalog manager for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Dict, List, Optional, Any
|
|
11
|
+
from packaging import version as pkg_version
|
|
12
|
+
|
|
13
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
14
|
+
from mcp_proxy_adapter.commands.dependency_manager import dependency_manager
|
|
15
|
+
from mcp_proxy_adapter.config import config
|
|
16
|
+
from .command_catalog import CommandCatalog
|
|
17
|
+
from .catalog_loader import CatalogLoader
|
|
18
|
+
from .catalog_syncer import CatalogSyncer
|
|
19
|
+
from .dependency_manager import DependencyManager
|
|
20
|
+
|
|
21
|
+
# Try to import requests, but don't fail if not available
|
|
22
|
+
try:
|
|
23
|
+
import requests
|
|
24
|
+
REQUESTS_AVAILABLE = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
REQUESTS_AVAILABLE = False
|
|
27
|
+
get_global_logger().warning(
|
|
28
|
+
"requests library not available, HTTP/HTTPS functionality will be limited"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CatalogManager:
|
|
33
|
+
"""
|
|
34
|
+
Manager for command catalog operations.
|
|
35
|
+
|
|
36
|
+
Handles loading, syncing, and managing command catalogs from various sources.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, catalog_dir: str):
|
|
40
|
+
"""
|
|
41
|
+
Initialize catalog manager.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
catalog_dir: Directory for catalog storage
|
|
45
|
+
"""
|
|
46
|
+
self.catalog_dir = Path(catalog_dir)
|
|
47
|
+
self.logger = get_global_logger()
|
|
48
|
+
|
|
49
|
+
# Initialize components
|
|
50
|
+
self.loader = CatalogLoader()
|
|
51
|
+
self.syncer = CatalogSyncer(catalog_dir)
|
|
52
|
+
self.dependency_manager = DependencyManager()
|
|
53
|
+
|
|
54
|
+
# Load existing catalog
|
|
55
|
+
self.catalog: Dict[str, CommandCatalog] = {}
|
|
56
|
+
self._load_catalog()
|
|
57
|
+
|
|
58
|
+
def _load_catalog(self) -> None:
|
|
59
|
+
"""Load catalog from local storage."""
|
|
60
|
+
catalog_file = self.catalog_dir / "catalog.json"
|
|
61
|
+
self.catalog = self.loader.load_catalog_from_file(catalog_file)
|
|
62
|
+
|
|
63
|
+
def _save_catalog(self) -> None:
|
|
64
|
+
"""Save catalog to local storage."""
|
|
65
|
+
catalog_file = self.catalog_dir / "catalog.json"
|
|
66
|
+
self.loader.save_catalog_to_file(self.catalog, catalog_file)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def sync_with_servers(self, server_urls: List[str]) -> Dict[str, Any]:
|
|
70
|
+
"""
|
|
71
|
+
Synchronize catalog with remote servers.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
server_urls: List of server URLs to sync with
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Dictionary with sync results
|
|
78
|
+
"""
|
|
79
|
+
return self.syncer.sync_with_servers(server_urls)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _extract_metadata_from_file(self, file_path: str) -> Dict[str, Any]:
|
|
86
|
+
"""
|
|
87
|
+
Extract metadata from command file.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
file_path: Path to command file
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Dictionary of extracted metadata
|
|
94
|
+
"""
|
|
95
|
+
metadata = {}
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
99
|
+
content = f.read()
|
|
100
|
+
|
|
101
|
+
# Extract basic metadata
|
|
102
|
+
for line in content.split('\n'):
|
|
103
|
+
line = line.strip()
|
|
104
|
+
if line.startswith('__version__'):
|
|
105
|
+
metadata['version'] = line.split('=')[1].strip().strip('"\'')
|
|
106
|
+
elif line.startswith('__author__'):
|
|
107
|
+
metadata['author'] = line.split('=')[1].strip().strip('"\'')
|
|
108
|
+
elif line.startswith('__description__'):
|
|
109
|
+
metadata['description'] = line.split('=')[1].strip().strip('"\'')
|
|
110
|
+
elif line.startswith('__category__'):
|
|
111
|
+
metadata['category'] = line.split('=')[1].strip().strip('"\'')
|
|
112
|
+
elif line.startswith('__email__'):
|
|
113
|
+
metadata['email'] = line.split('=')[1].strip().strip('"\'')
|
|
114
|
+
elif line.startswith('__depends__'):
|
|
115
|
+
deps_str = line.split('=')[1].strip().strip('[]"\'')
|
|
116
|
+
if deps_str:
|
|
117
|
+
metadata['depends'] = [dep.strip().strip('"\'') for dep in deps_str.split(',')]
|
|
118
|
+
|
|
119
|
+
except Exception as e:
|
|
120
|
+
self.logger.error(f"Failed to extract metadata from {file_path}: {e}")
|
|
121
|
+
|
|
122
|
+
return metadata
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Catalog synchronization utilities for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Dict, List, Any, Optional
|
|
10
|
+
from packaging import version as pkg_version
|
|
11
|
+
|
|
12
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
13
|
+
from .command_catalog import CommandCatalog
|
|
14
|
+
from .catalog_loader import CatalogLoader
|
|
15
|
+
from .dependency_manager import DependencyManager
|
|
16
|
+
|
|
17
|
+
# Try to import requests, but don't fail if not available
|
|
18
|
+
try:
|
|
19
|
+
import requests
|
|
20
|
+
REQUESTS_AVAILABLE = True
|
|
21
|
+
except ImportError:
|
|
22
|
+
REQUESTS_AVAILABLE = False
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class CatalogSyncer:
|
|
26
|
+
"""Synchronizer for command catalogs."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, catalog_dir: str):
|
|
29
|
+
"""
|
|
30
|
+
Initialize catalog syncer.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
catalog_dir: Directory for catalog storage
|
|
34
|
+
"""
|
|
35
|
+
self.catalog_dir = Path(catalog_dir)
|
|
36
|
+
self.logger = get_global_logger()
|
|
37
|
+
self.loader = CatalogLoader()
|
|
38
|
+
self.dependency_manager = DependencyManager()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _should_download_command(self, command_name: str, server_cmd: CommandCatalog) -> bool:
|
|
42
|
+
"""
|
|
43
|
+
Check if command should be downloaded.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
command_name: Name of the command
|
|
47
|
+
server_cmd: Server command catalog entry
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
True if command should be downloaded, False otherwise
|
|
51
|
+
"""
|
|
52
|
+
# Check if command exists locally
|
|
53
|
+
local_file = self.catalog_dir / f"{command_name}.py"
|
|
54
|
+
if not local_file.exists():
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
# Check version
|
|
58
|
+
try:
|
|
59
|
+
local_version = self._get_local_version(command_name)
|
|
60
|
+
if local_version:
|
|
61
|
+
return pkg_version.parse(server_cmd.version) > pkg_version.parse(local_version)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
self.logger.warning(f"Failed to compare versions for {command_name}: {e}")
|
|
64
|
+
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
def _download_command(self, command_name: str, server_cmd: CommandCatalog) -> bool:
|
|
68
|
+
"""
|
|
69
|
+
Download command from server.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
command_name: Name of the command
|
|
73
|
+
server_cmd: Server command catalog entry
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
True if download successful, False otherwise
|
|
77
|
+
"""
|
|
78
|
+
if not REQUESTS_AVAILABLE:
|
|
79
|
+
self.logger.error("requests library not available, cannot download command")
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
# Download command file
|
|
84
|
+
response = requests.get(server_cmd.source_url, timeout=30)
|
|
85
|
+
response.raise_for_status()
|
|
86
|
+
|
|
87
|
+
# Save to local file
|
|
88
|
+
local_file = self.catalog_dir / f"{command_name}.py"
|
|
89
|
+
with open(local_file, 'w', encoding='utf-8') as f:
|
|
90
|
+
f.write(response.text)
|
|
91
|
+
|
|
92
|
+
# Update local catalog
|
|
93
|
+
server_cmd.file_path = str(local_file)
|
|
94
|
+
self._update_local_catalog(command_name, server_cmd)
|
|
95
|
+
|
|
96
|
+
return True
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
self.logger.error(f"Failed to download command {command_name}: {e}")
|
|
100
|
+
return False
|
|
101
|
+
|
|
102
|
+
def _get_local_version(self, command_name: str) -> Optional[str]:
|
|
103
|
+
"""
|
|
104
|
+
Get local version of command.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
command_name: Name of the command
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Local version string or None
|
|
111
|
+
"""
|
|
112
|
+
try:
|
|
113
|
+
local_file = self.catalog_dir / f"{command_name}.py"
|
|
114
|
+
if local_file.exists():
|
|
115
|
+
with open(local_file, 'r', encoding='utf-8') as f:
|
|
116
|
+
content = f.read()
|
|
117
|
+
|
|
118
|
+
# Extract version from file content
|
|
119
|
+
for line in content.split('\n'):
|
|
120
|
+
if line.strip().startswith('__version__'):
|
|
121
|
+
return line.split('=')[1].strip().strip('"\'')
|
|
122
|
+
except Exception:
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
def _update_local_catalog(self, command_name: str, command_catalog: CommandCatalog) -> None:
|
|
128
|
+
"""
|
|
129
|
+
Update local catalog with command information.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
command_name: Name of the command
|
|
133
|
+
command_catalog: Command catalog entry
|
|
134
|
+
"""
|
|
135
|
+
try:
|
|
136
|
+
catalog_file = self.catalog_dir / "catalog.json"
|
|
137
|
+
if catalog_file.exists():
|
|
138
|
+
with open(catalog_file, 'r', encoding='utf-8') as f:
|
|
139
|
+
catalog_data = json.load(f)
|
|
140
|
+
else:
|
|
141
|
+
catalog_data = {}
|
|
142
|
+
|
|
143
|
+
catalog_data[command_name] = command_catalog.to_dict()
|
|
144
|
+
|
|
145
|
+
with open(catalog_file, 'w', encoding='utf-8') as f:
|
|
146
|
+
json.dump(catalog_data, f, indent=2, ensure_ascii=False)
|
|
147
|
+
|
|
148
|
+
except Exception as e:
|
|
149
|
+
self.logger.error(f"Failed to update local catalog for {command_name}: {e}")
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Command catalog data model for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, List, Optional, Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CommandCatalog:
|
|
12
|
+
"""
|
|
13
|
+
Represents a command in the catalog with metadata.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self, name: str, version: str, source_url: str, file_path: Optional[str] = None
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Initialize command catalog entry.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
name: Command name
|
|
24
|
+
version: Command version
|
|
25
|
+
source_url: Source URL for the command
|
|
26
|
+
file_path: Local file path (optional)
|
|
27
|
+
"""
|
|
28
|
+
self.name = name
|
|
29
|
+
self.version = version
|
|
30
|
+
self.source_url = source_url
|
|
31
|
+
self.file_path = file_path
|
|
32
|
+
self.metadata: Dict[str, Any] = {}
|
|
33
|
+
|
|
34
|
+
# Standard metadata fields
|
|
35
|
+
self.plugin: Optional[str] = None
|
|
36
|
+
self.descr: Optional[str] = None
|
|
37
|
+
self.category: Optional[str] = None
|
|
38
|
+
self.author: Optional[str] = None
|
|
39
|
+
self.email: Optional[str] = None
|
|
40
|
+
self.depends: Optional[List[str]] = None # New field for dependencies
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Dependency management for command catalogs.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DependencyManager:
|
|
15
|
+
"""Manager for command dependencies."""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
"""Initialize dependency manager."""
|
|
19
|
+
self.logger = get_global_logger()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _is_package_installed(self, package_name: str) -> bool:
|
|
24
|
+
"""
|
|
25
|
+
Check if a package is installed.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
package_name: Name of the package to check
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
True if package is installed, False otherwise
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
__import__(package_name)
|
|
35
|
+
return True
|
|
36
|
+
except ImportError:
|
|
37
|
+
return False
|