mcp-proxy-adapter 2.0.1__py3-none-any.whl → 6.9.50__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 +47 -0
- mcp_proxy_adapter/__main__.py +13 -0
- mcp_proxy_adapter/api/__init__.py +0 -0
- mcp_proxy_adapter/api/app.py +66 -0
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +400 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_context.py +356 -0
- mcp_proxy_adapter/api/core/registration_manager.py +307 -0
- mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +181 -0
- mcp_proxy_adapter/api/middleware/__init__.py +21 -0
- mcp_proxy_adapter/api/middleware/base.py +54 -0
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
- mcp_proxy_adapter/api/middleware/factory.py +147 -0
- mcp_proxy_adapter/api/middleware/logging.py +31 -0
- mcp_proxy_adapter/api/middleware/performance.py +51 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
- 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 +270 -0
- mcp_proxy_adapter/api/tool_integration.py +131 -0
- mcp_proxy_adapter/api/tools.py +163 -0
- 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 +105 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +94 -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 +132 -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 +338 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
- mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
- mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
- mcp_proxy_adapter/client/proxy.py +123 -0
- mcp_proxy_adapter/commands/__init__.py +66 -0
- mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
- mcp_proxy_adapter/commands/base.py +389 -0
- mcp_proxy_adapter/commands/builtin_commands.py +30 -0
- 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 +97 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
- mcp_proxy_adapter/commands/command_registry.py +298 -0
- mcp_proxy_adapter/commands/config_command.py +102 -0
- mcp_proxy_adapter/commands/dependency_container.py +40 -0
- mcp_proxy_adapter/commands/dependency_manager.py +143 -0
- mcp_proxy_adapter/commands/echo_command.py +48 -0
- mcp_proxy_adapter/commands/health_command.py +142 -0
- mcp_proxy_adapter/commands/help_command.py +175 -0
- mcp_proxy_adapter/commands/hooks.py +172 -0
- mcp_proxy_adapter/commands/key_management_command.py +484 -0
- mcp_proxy_adapter/commands/load_command.py +123 -0
- mcp_proxy_adapter/commands/plugins_command.py +246 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +76 -0
- 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 +136 -0
- mcp_proxy_adapter/commands/result.py +157 -0
- mcp_proxy_adapter/commands/role_test_command.py +99 -0
- mcp_proxy_adapter/commands/roles_management_command.py +502 -0
- mcp_proxy_adapter/commands/security_command.py +472 -0
- mcp_proxy_adapter/commands/settings_command.py +113 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
- mcp_proxy_adapter/commands/token_management_command.py +500 -0
- mcp_proxy_adapter/commands/transport_management_command.py +129 -0
- mcp_proxy_adapter/commands/unload_command.py +92 -0
- mcp_proxy_adapter/config.py +32 -0
- mcp_proxy_adapter/core/__init__.py +8 -0
- mcp_proxy_adapter/core/app_factory.py +560 -0
- mcp_proxy_adapter/core/app_runner.py +318 -0
- mcp_proxy_adapter/core/auth_validator.py +508 -0
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +481 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
- mcp_proxy_adapter/core/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/client.py +608 -0
- mcp_proxy_adapter/core/client_manager.py +271 -0
- mcp_proxy_adapter/core/client_security.py +411 -0
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +237 -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 +204 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +131 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +476 -0
- mcp_proxy_adapter/core/config_converter.py +252 -0
- mcp_proxy_adapter/core/config_validator.py +211 -0
- mcp_proxy_adapter/core/crl_utils.py +362 -0
- mcp_proxy_adapter/core/errors.py +276 -0
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +250 -0
- mcp_proxy_adapter/core/mtls_asgi.py +140 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/mtls_proxy.py +229 -0
- mcp_proxy_adapter/core/mtls_server.py +154 -0
- mcp_proxy_adapter/core/protocol_manager.py +232 -0
- mcp_proxy_adapter/core/proxy/__init__.py +19 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +184 -0
- mcp_proxy_adapter/core/proxy_registration.py +80 -0
- mcp_proxy_adapter/core/role_utils.py +103 -0
- mcp_proxy_adapter/core/security_adapter.py +343 -0
- mcp_proxy_adapter/core/security_factory.py +96 -0
- mcp_proxy_adapter/core/security_integration.py +342 -0
- mcp_proxy_adapter/core/server_adapter.py +251 -0
- mcp_proxy_adapter/core/server_engine.py +217 -0
- mcp_proxy_adapter/core/settings.py +260 -0
- mcp_proxy_adapter/core/signal_handler.py +107 -0
- mcp_proxy_adapter/core/ssl_utils.py +161 -0
- mcp_proxy_adapter/core/transport_manager.py +153 -0
- mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
- mcp_proxy_adapter/core/utils.py +101 -0
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +219 -0
- mcp_proxy_adapter/core/validation/file_validator.py +131 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +205 -0
- mcp_proxy_adapter/core/validation/security_validator.py +140 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +58 -0
- mcp_proxy_adapter/examples/__init__.py +16 -0
- 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 +52 -0
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
- mcp_proxy_adapter/examples/check_config.py +413 -0
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/config_builder.py +234 -0
- mcp_proxy_adapter/examples/config_cli.py +282 -0
- mcp_proxy_adapter/examples/create_test_configs.py +174 -0
- mcp_proxy_adapter/examples/debug_request_state.py +130 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
- mcp_proxy_adapter/examples/demo_client.py +287 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
- mcp_proxy_adapter/examples/full_application/main.py +311 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +161 -0
- mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
- mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
- mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
- mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
- mcp_proxy_adapter/examples/generate_config.py +502 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
- 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 +208 -0
- mcp_proxy_adapter/examples/run_example.py +77 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
- 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 +72 -0
- 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 +235 -0
- mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
- mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
- mcp_proxy_adapter/examples/test_config.py +205 -0
- mcp_proxy_adapter/examples/test_config_builder.py +110 -0
- mcp_proxy_adapter/examples/test_examples.py +308 -0
- mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
- mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
- mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
- mcp_proxy_adapter/examples/universal_client.py +674 -0
- mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +311 -0
- mcp_proxy_adapter/openapi.py +375 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/schemas/roles.json +37 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/version.py +5 -0
- mcp_proxy_adapter-6.9.50.dist-info/METADATA +1088 -0
- mcp_proxy_adapter-6.9.50.dist-info/RECORD +242 -0
- {mcp_proxy_adapter-2.0.1.dist-info → mcp_proxy_adapter-6.9.50.dist-info}/WHEEL +1 -1
- mcp_proxy_adapter-6.9.50.dist-info/entry_points.txt +14 -0
- mcp_proxy_adapter-6.9.50.dist-info/top_level.txt +1 -0
- adapters/__init__.py +0 -16
- analyzers/__init__.py +0 -14
- analyzers/docstring_analyzer.py +0 -199
- analyzers/type_analyzer.py +0 -151
- cli/__init__.py +0 -12
- cli/__main__.py +0 -79
- cli/command_runner.py +0 -233
- dispatchers/__init__.py +0 -14
- dispatchers/base_dispatcher.py +0 -85
- dispatchers/json_rpc_dispatcher.py +0 -198
- generators/__init__.py +0 -14
- generators/endpoint_generator.py +0 -172
- generators/openapi_generator.py +0 -254
- generators/rest_api_generator.py +0 -207
- mcp_proxy_adapter-2.0.1.dist-info/METADATA +0 -272
- mcp_proxy_adapter-2.0.1.dist-info/RECORD +0 -28
- mcp_proxy_adapter-2.0.1.dist-info/licenses/LICENSE +0 -21
- mcp_proxy_adapter-2.0.1.dist-info/top_level.txt +0 -7
- openapi_schema/__init__.py +0 -38
- openapi_schema/command_registry.py +0 -312
- openapi_schema/rest_schema.py +0 -510
- openapi_schema/rpc_generator.py +0 -307
- openapi_schema/rpc_schema.py +0 -416
- validators/__init__.py +0 -14
- validators/base_validator.py +0 -23
- validators/docstring_validator.py +0 -75
- validators/metadata_validator.py +0 -76
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Main command registry for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
from mcp_proxy_adapter.commands.base import Command
|
|
10
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
11
|
+
from .command_loader import CommandLoader
|
|
12
|
+
from .command_manager import CommandManager
|
|
13
|
+
from .command_info import CommandInfo
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class CommandRegistry:
|
|
17
|
+
"""
|
|
18
|
+
Registry for registering and finding commands.
|
|
19
|
+
|
|
20
|
+
Supports three types of commands:
|
|
21
|
+
- Builtin: Core commands that come with the framework
|
|
22
|
+
- Custom: User-defined commands
|
|
23
|
+
- Loaded: Commands loaded from external sources
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
"""Initialize command registry."""
|
|
28
|
+
self.logger = get_global_logger()
|
|
29
|
+
|
|
30
|
+
# Command storage
|
|
31
|
+
self._commands: Dict[str, Type[Command]] = {}
|
|
32
|
+
self._instances: Dict[str, Command] = {}
|
|
33
|
+
self._command_types: Dict[str, str] = {} # "builtin", "custom", "loaded"
|
|
34
|
+
|
|
35
|
+
# Initialize components
|
|
36
|
+
self._loader = CommandLoader()
|
|
37
|
+
self._manager = CommandManager()
|
|
38
|
+
self._info = CommandInfo()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def register_loaded(self, command: Union[Type[Command], Command]) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Register a loaded command.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
command: Command class or instance to register
|
|
48
|
+
"""
|
|
49
|
+
self._register_command(command, "loaded")
|
|
50
|
+
|
|
51
|
+
def _register_command(self, command: Union[Type[Command], Command], cmd_type: str) -> None:
|
|
52
|
+
"""
|
|
53
|
+
Register a command.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
command: Command class or instance to register
|
|
57
|
+
cmd_type: Type of command ("builtin", "custom", "loaded")
|
|
58
|
+
"""
|
|
59
|
+
if isinstance(command, Command):
|
|
60
|
+
# Register instance
|
|
61
|
+
command_name = self._manager._get_command_name(command.__class__)
|
|
62
|
+
self._instances[command_name] = command
|
|
63
|
+
self._commands[command_name] = command.__class__
|
|
64
|
+
else:
|
|
65
|
+
# Register class
|
|
66
|
+
command_name = self._manager._get_command_name(command)
|
|
67
|
+
self._commands[command_name] = command
|
|
68
|
+
|
|
69
|
+
self._command_types[command_name] = cmd_type
|
|
70
|
+
self.logger.info(f"Registered {cmd_type} command: {command_name}")
|
|
71
|
+
|
|
72
|
+
def load_command_from_source(self, source: str) -> Dict[str, Any]:
|
|
73
|
+
"""
|
|
74
|
+
Load command from source.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
source: Source string - local path, URL, or command name from registry
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Dictionary with loading result information
|
|
81
|
+
"""
|
|
82
|
+
result = self._loader.load_command_from_source(source)
|
|
83
|
+
|
|
84
|
+
if result["success"]:
|
|
85
|
+
# Register loaded commands
|
|
86
|
+
for command_class in result["commands"]:
|
|
87
|
+
self.register_loaded(command_class)
|
|
88
|
+
|
|
89
|
+
return result
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def command_exists(self, command_name: str) -> bool:
|
|
93
|
+
"""
|
|
94
|
+
Check if command exists.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
command_name: Name of the command
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
True if command exists, False otherwise
|
|
101
|
+
"""
|
|
102
|
+
return self._manager.command_exists(command_name, self._commands)
|
|
103
|
+
|
|
104
|
+
def get_command(self, command_name: str) -> Type[Command]:
|
|
105
|
+
"""
|
|
106
|
+
Get command class by name.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
command_name: Name of the command
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Command class
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
NotFoundError: If command not found
|
|
116
|
+
"""
|
|
117
|
+
return self._manager.get_command(command_name, self._commands)
|
|
118
|
+
|
|
119
|
+
def get_command_instance(self, command_name: str) -> Command:
|
|
120
|
+
"""
|
|
121
|
+
Get command instance by name.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
command_name: Name of the command
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Command instance
|
|
128
|
+
|
|
129
|
+
Raises:
|
|
130
|
+
NotFoundError: If command not found
|
|
131
|
+
"""
|
|
132
|
+
return self._manager.get_command_instance(command_name, self._commands, self._instances)
|
|
133
|
+
|
|
134
|
+
def has_instance(self, command_name: str) -> bool:
|
|
135
|
+
"""
|
|
136
|
+
Check if command has instance.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
command_name: Name of the command
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
True if command has instance, False otherwise
|
|
143
|
+
"""
|
|
144
|
+
return self._manager.has_instance(command_name, self._instances)
|
|
145
|
+
|
|
146
|
+
def get_all_commands(self) -> Dict[str, Type[Command]]:
|
|
147
|
+
"""
|
|
148
|
+
Get all registered commands.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Dictionary of all commands
|
|
152
|
+
"""
|
|
153
|
+
return self._manager.get_all_commands(self._commands)
|
|
154
|
+
|
|
155
|
+
def get_commands_by_type(self) -> Dict[str, Dict[str, Type[Command]]]:
|
|
156
|
+
"""
|
|
157
|
+
Get commands grouped by type.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Dictionary of commands grouped by type
|
|
161
|
+
"""
|
|
162
|
+
return self._manager.get_commands_by_type(self._commands, self._command_types)
|
|
163
|
+
|
|
164
|
+
def get_all_metadata(self) -> Dict[str, Dict[str, Any]]:
|
|
165
|
+
"""
|
|
166
|
+
Get metadata for all commands.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Dictionary of command metadata
|
|
170
|
+
"""
|
|
171
|
+
return self._manager.get_all_metadata(self._commands, self._command_types)
|
|
172
|
+
|
|
173
|
+
def clear(self) -> None:
|
|
174
|
+
"""Clear all commands and instances."""
|
|
175
|
+
self._manager.clear(self._commands, self._instances, self._command_types)
|
|
176
|
+
self.logger.info("Cleared all commands")
|
|
177
|
+
|
|
178
|
+
def get_all_commands_info(self) -> Dict[str, Any]:
|
|
179
|
+
"""
|
|
180
|
+
Get comprehensive information about all commands.
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Dictionary with command information
|
|
184
|
+
"""
|
|
185
|
+
return self._info.get_all_commands_info(self._commands, self._command_types)
|
|
186
|
+
|
|
187
|
+
def get_command_info(self, command_name: str) -> Optional[Dict[str, Any]]:
|
|
188
|
+
"""
|
|
189
|
+
Get detailed information about a specific command.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
command_name: Name of the command
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Dictionary with command information or None if not found
|
|
196
|
+
"""
|
|
197
|
+
if command_name not in self._commands:
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
return self._info.get_command_info(
|
|
201
|
+
command_name,
|
|
202
|
+
self._commands[command_name],
|
|
203
|
+
self._command_types
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def _load_all_commands(self) -> Dict[str, int]:
|
|
207
|
+
"""
|
|
208
|
+
Load all commands from configured directories.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
Dictionary with loading statistics
|
|
212
|
+
"""
|
|
213
|
+
return self._manager._load_all_commands(self._commands, self._command_types)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# Global registry instance
|
|
217
|
+
registry = CommandRegistry()
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Reload command for configuration and command discovery.
|
|
3
|
+
|
|
4
|
+
This command allows reloading configuration and rediscovering commands
|
|
5
|
+
without restarting the server.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
from mcp_proxy_adapter.commands.base import Command
|
|
11
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
|
12
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ReloadResult:
|
|
16
|
+
"""
|
|
17
|
+
Result of reload operation.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
config_reloaded: bool,
|
|
23
|
+
builtin_commands: int,
|
|
24
|
+
custom_commands: int,
|
|
25
|
+
loaded_commands: int,
|
|
26
|
+
remote_commands: int = 0,
|
|
27
|
+
total_commands: int = 0,
|
|
28
|
+
server_restart_required: bool = True,
|
|
29
|
+
success: bool = True,
|
|
30
|
+
error_message: Optional[str] = None,
|
|
31
|
+
):
|
|
32
|
+
"""
|
|
33
|
+
Initialize reload result.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
config_reloaded: Whether configuration was reloaded successfully
|
|
37
|
+
builtin_commands: Number of built-in commands registered
|
|
38
|
+
custom_commands: Number of custom commands registered
|
|
39
|
+
loaded_commands: Number of commands loaded from directory
|
|
40
|
+
total_commands: Total number of commands after reload
|
|
41
|
+
server_restart_required: Whether server restart is required
|
|
42
|
+
success: Whether reload was successful
|
|
43
|
+
error_message: Error message if reload failed
|
|
44
|
+
"""
|
|
45
|
+
self.config_reloaded = config_reloaded
|
|
46
|
+
self.builtin_commands = builtin_commands
|
|
47
|
+
self.custom_commands = custom_commands
|
|
48
|
+
self.loaded_commands = loaded_commands
|
|
49
|
+
self.remote_commands = remote_commands
|
|
50
|
+
self.total_commands = total_commands
|
|
51
|
+
self.server_restart_required = server_restart_required
|
|
52
|
+
self.success = success
|
|
53
|
+
self.error_message = error_message
|
|
54
|
+
|
|
55
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
56
|
+
"""
|
|
57
|
+
Convert result to dictionary.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Dictionary representation of the result.
|
|
61
|
+
"""
|
|
62
|
+
return {
|
|
63
|
+
"success": self.success,
|
|
64
|
+
"config_reloaded": self.config_reloaded,
|
|
65
|
+
"builtin_commands": self.builtin_commands,
|
|
66
|
+
"custom_commands": self.custom_commands,
|
|
67
|
+
"loaded_commands": self.loaded_commands,
|
|
68
|
+
"remote_commands": self.remote_commands,
|
|
69
|
+
"total_commands": self.total_commands,
|
|
70
|
+
"server_restart_required": self.server_restart_required,
|
|
71
|
+
"message": "Server restart required to apply configuration changes",
|
|
72
|
+
"error_message": self.error_message,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ReloadCommand(Command):
|
|
79
|
+
"""
|
|
80
|
+
Command for reloading configuration and rediscovering commands.
|
|
81
|
+
Uses the unified initialization logic.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
name = "reload"
|
|
85
|
+
|
|
86
|
+
async def execute(self, **params) -> ReloadResult:
|
|
87
|
+
"""
|
|
88
|
+
Execute reload command.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
**params: Command parameters (config_path)
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
ReloadResult with reload information
|
|
95
|
+
"""
|
|
96
|
+
try:
|
|
97
|
+
get_global_logger().info("🔄 Starting configuration and commands reload...")
|
|
98
|
+
|
|
99
|
+
# Get config path from parameters
|
|
100
|
+
config_path = params.get("config_path")
|
|
101
|
+
if not config_path:
|
|
102
|
+
get_global_logger().warning("No config_path provided, using default configuration")
|
|
103
|
+
|
|
104
|
+
# Perform reload using unified initialization
|
|
105
|
+
reload_info = await registry.reload_system(config_path=config_path)
|
|
106
|
+
|
|
107
|
+
# Create result
|
|
108
|
+
result = ReloadResult(
|
|
109
|
+
config_reloaded=reload_info.get("config_reloaded", False),
|
|
110
|
+
builtin_commands=reload_info.get("builtin_commands", 0),
|
|
111
|
+
custom_commands=reload_info.get("custom_commands", 0),
|
|
112
|
+
loaded_commands=reload_info.get("loaded_commands", 0),
|
|
113
|
+
remote_commands=reload_info.get("remote_commands", 0),
|
|
114
|
+
total_commands=reload_info.get("total_commands", 0),
|
|
115
|
+
server_restart_required=True, # Default to True as per tests
|
|
116
|
+
success=True,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
get_global_logger().info(f"✅ Reload completed successfully: {result.to_dict()}")
|
|
120
|
+
return result
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
get_global_logger().error(f"❌ Reload failed: {str(e)}")
|
|
124
|
+
return ReloadResult(
|
|
125
|
+
config_reloaded=False,
|
|
126
|
+
builtin_commands=0,
|
|
127
|
+
custom_commands=0,
|
|
128
|
+
loaded_commands=0,
|
|
129
|
+
remote_commands=0,
|
|
130
|
+
total_commands=0,
|
|
131
|
+
server_restart_required=False,
|
|
132
|
+
success=False,
|
|
133
|
+
error_message=str(e),
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
@classmethod
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module with base classes for command results.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from abc import ABC, abstractmethod
|
|
7
|
+
from typing import TypeVar, Dict, Any, Optional
|
|
8
|
+
|
|
9
|
+
T = TypeVar("T", bound="CommandResult")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CommandResult(ABC):
|
|
13
|
+
"""
|
|
14
|
+
Base abstract class for command execution results.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
19
|
+
"""
|
|
20
|
+
Converts result to dictionary for serialization.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
Dictionary with result data.
|
|
24
|
+
"""
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def get_schema(cls) -> Dict[str, Any]:
|
|
30
|
+
"""Get JSON schema for the result."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def from_dict(cls, data: Dict[str, Any]) -> "CommandResult":
|
|
35
|
+
"""Create result from dictionary."""
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class SuccessResult(CommandResult):
|
|
40
|
+
"""
|
|
41
|
+
Base class for successful command results.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self, data: Optional[Dict[str, Any]] = None, message: Optional[str] = None
|
|
46
|
+
):
|
|
47
|
+
"""
|
|
48
|
+
Initialize successful result.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
data: Result data.
|
|
52
|
+
message: Result message.
|
|
53
|
+
"""
|
|
54
|
+
self.data = data or {}
|
|
55
|
+
self.message = message
|
|
56
|
+
|
|
57
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
58
|
+
"""
|
|
59
|
+
Converts result to dictionary for serialization.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Dictionary with result data.
|
|
63
|
+
"""
|
|
64
|
+
result = {"success": True}
|
|
65
|
+
if self.data:
|
|
66
|
+
result["data"] = self.data
|
|
67
|
+
if self.message:
|
|
68
|
+
result["message"] = self.message
|
|
69
|
+
return result
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def get_schema(cls) -> Dict[str, Any]:
|
|
73
|
+
"""Get JSON schema for success result."""
|
|
74
|
+
return {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {
|
|
77
|
+
"success": {"type": "boolean", "const": True},
|
|
78
|
+
"data": {"type": "object"},
|
|
79
|
+
"message": {"type": "string"}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def from_dict(cls, data: Dict[str, Any]) -> "SuccessResult":
|
|
85
|
+
"""Create success result from dictionary."""
|
|
86
|
+
return cls(
|
|
87
|
+
data=data.get("data"),
|
|
88
|
+
message=data.get("message")
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ErrorResult(CommandResult):
|
|
93
|
+
"""
|
|
94
|
+
Base class for command results with error.
|
|
95
|
+
|
|
96
|
+
This class follows the JSON-RPC 2.0 error object format:
|
|
97
|
+
https://www.jsonrpc.org/specification#error_object
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
def __init__(
|
|
101
|
+
self, message: str, code: int = -32000, details: Optional[Dict[str, Any]] = None
|
|
102
|
+
):
|
|
103
|
+
"""
|
|
104
|
+
Initialize error result.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
message: Error message.
|
|
108
|
+
code: Error code (following JSON-RPC 2.0 spec).
|
|
109
|
+
details: Additional error details.
|
|
110
|
+
"""
|
|
111
|
+
self.message = message
|
|
112
|
+
self.error = message # For backward compatibility with tests
|
|
113
|
+
self.code = code
|
|
114
|
+
self.details = details or {}
|
|
115
|
+
|
|
116
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
117
|
+
"""
|
|
118
|
+
Converts result to dictionary for serialization.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Dictionary with result data in JSON-RPC 2.0 error format.
|
|
122
|
+
"""
|
|
123
|
+
result = {
|
|
124
|
+
"success": False,
|
|
125
|
+
"error": {"code": self.code, "message": self.message},
|
|
126
|
+
}
|
|
127
|
+
if self.details:
|
|
128
|
+
result["error"]["data"] = self.details
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
@classmethod
|
|
132
|
+
def get_schema(cls) -> Dict[str, Any]:
|
|
133
|
+
"""Get JSON schema for error result."""
|
|
134
|
+
return {
|
|
135
|
+
"type": "object",
|
|
136
|
+
"properties": {
|
|
137
|
+
"success": {"type": "boolean", "const": False},
|
|
138
|
+
"error": {
|
|
139
|
+
"type": "object",
|
|
140
|
+
"properties": {
|
|
141
|
+
"code": {"type": "integer"},
|
|
142
|
+
"message": {"type": "string"},
|
|
143
|
+
"data": {"type": "object"}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ErrorResult":
|
|
151
|
+
"""Create error result from dictionary."""
|
|
152
|
+
error_data = data.get("error", {})
|
|
153
|
+
return cls(
|
|
154
|
+
code=error_data.get("code", -32603),
|
|
155
|
+
message=error_data.get("message", "Internal error"),
|
|
156
|
+
details=error_data.get("data")
|
|
157
|
+
)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Role Test Command
|
|
3
|
+
|
|
4
|
+
This command tests role-based access control by checking user permissions.
|
|
5
|
+
|
|
6
|
+
Author: Vasiliy Zdanovskiy
|
|
7
|
+
email: vasilyvz@gmail.com
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from mcp_proxy_adapter.commands.base import Command
|
|
12
|
+
from mcp_proxy_adapter.commands.result import SuccessResult
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class RoleTestCommandResult(SuccessResult):
|
|
20
|
+
"""Result for role test command."""
|
|
21
|
+
|
|
22
|
+
def __init__(self, user_role: str, permissions: list, action: str, allowed: bool):
|
|
23
|
+
"""
|
|
24
|
+
Initialize role test result.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
user_role: User's role
|
|
28
|
+
permissions: User's permissions
|
|
29
|
+
action: Action being tested
|
|
30
|
+
allowed: Whether action is allowed
|
|
31
|
+
"""
|
|
32
|
+
super().__init__()
|
|
33
|
+
self.user_role = user_role
|
|
34
|
+
self.permissions = permissions
|
|
35
|
+
self.action = action
|
|
36
|
+
self.allowed = allowed
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@classmethod
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class RoleTestCommand(Command):
|
|
43
|
+
"""Test role-based access control."""
|
|
44
|
+
|
|
45
|
+
name = "roletest"
|
|
46
|
+
descr = "Test role-based access control"
|
|
47
|
+
category = "security"
|
|
48
|
+
author = "Vasiliy Zdanovskiy"
|
|
49
|
+
email = "vasilyvz@gmail.com"
|
|
50
|
+
|
|
51
|
+
async def execute(self, **kwargs) -> RoleTestCommandResult:
|
|
52
|
+
"""
|
|
53
|
+
Execute role test command.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
**kwargs: Command parameters including context
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
RoleTestCommandResult
|
|
60
|
+
"""
|
|
61
|
+
# Extract parameters
|
|
62
|
+
action = kwargs.get("action", "read")
|
|
63
|
+
context = kwargs.get("context", {})
|
|
64
|
+
|
|
65
|
+
# Get user info from context
|
|
66
|
+
user_role = "guest" # Default
|
|
67
|
+
permissions = ["read"] # Default
|
|
68
|
+
|
|
69
|
+
if context:
|
|
70
|
+
user_info = context.get("user", {})
|
|
71
|
+
user_role = user_info.get("role", "guest")
|
|
72
|
+
permissions = user_info.get("permissions", ["read"])
|
|
73
|
+
|
|
74
|
+
# Check if action is allowed
|
|
75
|
+
allowed = self._check_permission(action, permissions)
|
|
76
|
+
|
|
77
|
+
get_global_logger().info(f"Role test: user={user_role}, action={action}, allowed={allowed}")
|
|
78
|
+
|
|
79
|
+
return RoleTestCommandResult(user_role, permissions, action, allowed)
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
|
|
83
|
+
def _check_permission(self, action: str, permissions: list) -> bool:
|
|
84
|
+
"""
|
|
85
|
+
Check if action is allowed for given permissions.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
action: Action to check
|
|
89
|
+
permissions: User permissions
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
True if allowed, False otherwise
|
|
93
|
+
"""
|
|
94
|
+
# Admin has all permissions
|
|
95
|
+
if "*" in permissions:
|
|
96
|
+
return True
|
|
97
|
+
|
|
98
|
+
# Check specific permission
|
|
99
|
+
return action in permissions
|