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,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dynamic Calculator Command
|
|
3
|
+
This module demonstrates a dynamically loaded command implementation for the full application example.
|
|
4
|
+
Author: Vasiliy Zdanovskiy
|
|
5
|
+
email: vasilyvz@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
|
9
|
+
from mcp_proxy_adapter.commands.result import CommandResult
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CalculatorResult(CommandResult):
|
|
13
|
+
"""Result class for calculator command."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, operation: str, result: float, expression: str):
|
|
16
|
+
self.operation = operation
|
|
17
|
+
self.result = result
|
|
18
|
+
self.expression = expression
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DynamicCalculatorCommand(BaseCommand):
|
|
24
|
+
"""Dynamic calculator command implementation."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def execute(self, params: Dict[str, Any]) -> CalculatorResult:
|
|
30
|
+
"""Execute the calculator command."""
|
|
31
|
+
operation = params.get("operation")
|
|
32
|
+
a = params.get("a")
|
|
33
|
+
b = params.get("b")
|
|
34
|
+
if operation == "add":
|
|
35
|
+
result = a + b
|
|
36
|
+
expression = f"{a} + {b}"
|
|
37
|
+
elif operation == "subtract":
|
|
38
|
+
result = a - b
|
|
39
|
+
expression = f"{a} - {b}"
|
|
40
|
+
elif operation == "multiply":
|
|
41
|
+
result = a * b
|
|
42
|
+
expression = f"{a} * {b}"
|
|
43
|
+
elif operation == "divide":
|
|
44
|
+
if b == 0:
|
|
45
|
+
raise ValueError("Division by zero is not allowed")
|
|
46
|
+
result = a / b
|
|
47
|
+
expression = f"{a} / {b}"
|
|
48
|
+
else:
|
|
49
|
+
raise ValueError(f"Unknown operation: {operation}")
|
|
50
|
+
return CalculatorResult(
|
|
51
|
+
operation=operation, result=result, expression=expression
|
|
52
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Echo command implementation.
|
|
3
|
+
"""
|
|
4
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
|
5
|
+
from mcp_proxy_adapter.core.errors import MicroserviceError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EchoCommand(BaseCommand):
|
|
9
|
+
"""Echo command that returns the input message."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
super().__init__()
|
|
13
|
+
self.name = "echo"
|
|
14
|
+
self.description = "Echo command that returns the input message"
|
|
15
|
+
self.version = "1.0.0"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def execute(self, params: dict) -> dict:
|
|
19
|
+
"""Execute echo command."""
|
|
20
|
+
try:
|
|
21
|
+
message = params.get("message", "")
|
|
22
|
+
return {
|
|
23
|
+
"echo": message,
|
|
24
|
+
"timestamp": self._get_timestamp()
|
|
25
|
+
}
|
|
26
|
+
except Exception as e:
|
|
27
|
+
raise MicroserviceError(f"Echo command failed: {str(e)}")
|
|
28
|
+
|
|
29
|
+
def _get_timestamp(self):
|
|
30
|
+
"""Get current timestamp."""
|
|
31
|
+
import time
|
|
32
|
+
return time.time()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Help command implementation.
|
|
3
|
+
"""
|
|
4
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
|
5
|
+
from mcp_proxy_adapter.core.errors import MicroserviceError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HelpCommand(BaseCommand):
|
|
9
|
+
"""Help command that provides usage information."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
super().__init__()
|
|
13
|
+
self.name = "help"
|
|
14
|
+
self.description = "Get help information"
|
|
15
|
+
self.version = "1.0.0"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def execute(self, params: dict) -> dict:
|
|
19
|
+
"""Execute help command."""
|
|
20
|
+
try:
|
|
21
|
+
command = params.get("command")
|
|
22
|
+
|
|
23
|
+
if command:
|
|
24
|
+
# Get help for specific command
|
|
25
|
+
help_info = self._get_command_help(command)
|
|
26
|
+
return {
|
|
27
|
+
"command": command,
|
|
28
|
+
"help": help_info,
|
|
29
|
+
"timestamp": self._get_timestamp()
|
|
30
|
+
}
|
|
31
|
+
else:
|
|
32
|
+
# Get general help
|
|
33
|
+
return {
|
|
34
|
+
"help": "MCP Proxy Adapter - Available commands: echo, list, health, help",
|
|
35
|
+
"usage": "Use 'help' with a command name to get specific help",
|
|
36
|
+
"timestamp": self._get_timestamp()
|
|
37
|
+
}
|
|
38
|
+
except Exception as e:
|
|
39
|
+
raise MicroserviceError(f"Help command failed: {str(e)}")
|
|
40
|
+
|
|
41
|
+
def _get_command_help(self, command: str) -> str:
|
|
42
|
+
"""Get help for specific command."""
|
|
43
|
+
help_map = {
|
|
44
|
+
"echo": "Echo command - returns the input message. Usage: {'message': 'your message'}",
|
|
45
|
+
"list": "List command - returns available commands. Usage: {}",
|
|
46
|
+
"health": "Health command - returns server health status. Usage: {}",
|
|
47
|
+
"help": "Help command - provides usage information. Usage: {'command': 'command_name'} (optional)"
|
|
48
|
+
}
|
|
49
|
+
return help_map.get(command, f"No help available for command '{command}'")
|
|
50
|
+
|
|
51
|
+
def _get_timestamp(self):
|
|
52
|
+
"""Get current timestamp."""
|
|
53
|
+
import time
|
|
54
|
+
return time.time()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""
|
|
2
|
+
List command implementation.
|
|
3
|
+
"""
|
|
4
|
+
from mcp_proxy_adapter.commands.base import BaseCommand
|
|
5
|
+
from mcp_proxy_adapter.core.errors import MicroserviceError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ListCommand(BaseCommand):
|
|
9
|
+
"""List command that returns available commands."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
super().__init__()
|
|
13
|
+
self.name = "list"
|
|
14
|
+
self.description = "List available commands"
|
|
15
|
+
self.version = "1.0.0"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async def execute(self, params: dict) -> dict:
|
|
19
|
+
"""Execute list command."""
|
|
20
|
+
try:
|
|
21
|
+
# This is a simplified list - in a real implementation,
|
|
22
|
+
# this would query the command registry
|
|
23
|
+
commands = [
|
|
24
|
+
{
|
|
25
|
+
"name": "echo",
|
|
26
|
+
"description": "Echo command that returns the input message",
|
|
27
|
+
"version": "1.0.0"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "list",
|
|
31
|
+
"description": "List available commands",
|
|
32
|
+
"version": "1.0.0"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "health",
|
|
36
|
+
"description": "Health check command",
|
|
37
|
+
"version": "1.0.0"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "help",
|
|
41
|
+
"description": "Help command",
|
|
42
|
+
"version": "1.0.0"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
"commands": commands,
|
|
48
|
+
"count": len(commands),
|
|
49
|
+
"timestamp": self._get_timestamp()
|
|
50
|
+
}
|
|
51
|
+
except Exception as e:
|
|
52
|
+
raise MicroserviceError(f"List command failed: {str(e)}")
|
|
53
|
+
|
|
54
|
+
def _get_timestamp(self):
|
|
55
|
+
"""Get current timestamp."""
|
|
56
|
+
import time
|
|
57
|
+
return time.time()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Application Hooks
|
|
3
|
+
This module demonstrates application-level hooks in the full application example.
|
|
4
|
+
Author: Vasiliy Zdanovskiy
|
|
5
|
+
email: vasilyvz@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ApplicationHooks:
|
|
15
|
+
"""Application-level hooks."""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Built-in Command Hooks
|
|
3
|
+
This module demonstrates hooks for built-in commands in the full application example.
|
|
4
|
+
Author: Vasiliy Zdanovskiy
|
|
5
|
+
email: vasilyvz@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BuiltinCommandHooks:
|
|
15
|
+
"""Hooks for built-in commands."""
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Full Application Example
|
|
4
|
+
This is a complete application that demonstrates all features of MCP Proxy Adapter framework:
|
|
5
|
+
- Built-in commands
|
|
6
|
+
- Custom commands
|
|
7
|
+
- Dynamically loaded commands
|
|
8
|
+
- Built-in command hooks
|
|
9
|
+
- Application hooks
|
|
10
|
+
Author: Vasiliy Zdanovskiy
|
|
11
|
+
email: vasilyvz@gmail.com
|
|
12
|
+
"""
|
|
13
|
+
import argparse
|
|
14
|
+
import asyncio
|
|
15
|
+
import json
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
from mcp_proxy_adapter.api.app import create_app
|
|
19
|
+
from mcp_proxy_adapter.core.server_engine import ServerEngineFactory
|
|
20
|
+
from mcp_proxy_adapter.core.server_adapter import ServerConfigAdapter
|
|
21
|
+
from mcp_proxy_adapter.client.proxy import ProxyClient
|
|
22
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def register_all_commands():
|
|
26
|
+
"""Register all available commands (built-in, load, queue)."""
|
|
27
|
+
from mcp_proxy_adapter.commands.load_command import LoadCommand
|
|
28
|
+
|
|
29
|
+
# Register load command
|
|
30
|
+
registry._commands["load"] = LoadCommand
|
|
31
|
+
registry._command_types["load"] = "builtin"
|
|
32
|
+
|
|
33
|
+
# Register queue commands (will fail gracefully if queuemgr not available)
|
|
34
|
+
try:
|
|
35
|
+
from mcp_proxy_adapter.commands.queue_commands import (
|
|
36
|
+
QueueAddJobCommand,
|
|
37
|
+
QueueStartJobCommand,
|
|
38
|
+
QueueStopJobCommand,
|
|
39
|
+
QueueDeleteJobCommand,
|
|
40
|
+
QueueGetJobStatusCommand,
|
|
41
|
+
QueueListJobsCommand,
|
|
42
|
+
QueueHealthCommand,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
registry._commands["queue_add_job"] = QueueAddJobCommand
|
|
46
|
+
registry._command_types["queue_add_job"] = "builtin"
|
|
47
|
+
registry._commands["queue_start_job"] = QueueStartJobCommand
|
|
48
|
+
registry._command_types["queue_start_job"] = "builtin"
|
|
49
|
+
registry._commands["queue_stop_job"] = QueueStopJobCommand
|
|
50
|
+
registry._command_types["queue_stop_job"] = "builtin"
|
|
51
|
+
registry._commands["queue_delete_job"] = QueueDeleteJobCommand
|
|
52
|
+
registry._command_types["queue_delete_job"] = "builtin"
|
|
53
|
+
registry._commands["queue_get_job_status"] = QueueGetJobStatusCommand
|
|
54
|
+
registry._command_types["queue_get_job_status"] = "builtin"
|
|
55
|
+
registry._commands["queue_list_jobs"] = QueueListJobsCommand
|
|
56
|
+
registry._command_types["queue_list_jobs"] = "builtin"
|
|
57
|
+
registry._commands["queue_health"] = QueueHealthCommand
|
|
58
|
+
registry._command_types["queue_health"] = "builtin"
|
|
59
|
+
print("✅ Queue commands registered")
|
|
60
|
+
except Exception as e:
|
|
61
|
+
print(f"⚠️ Queue commands not available: {e}")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def main():
|
|
65
|
+
"""Minimal runnable entrypoint for full application example."""
|
|
66
|
+
parser = argparse.ArgumentParser(description="MCP Proxy Adapter Full Application")
|
|
67
|
+
parser.add_argument("--config", required=True, help="Path to configuration file")
|
|
68
|
+
parser.add_argument("--port", type=int, help="Port to run server on (override)")
|
|
69
|
+
parser.add_argument("--host", default="0.0.0.0", help="Host to bind to")
|
|
70
|
+
args = parser.parse_args()
|
|
71
|
+
|
|
72
|
+
cfg_path = Path(args.config)
|
|
73
|
+
if not cfg_path.exists():
|
|
74
|
+
print(f"❌ Configuration file not found: {cfg_path}")
|
|
75
|
+
raise SystemExit(1)
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
with cfg_path.open("r", encoding="utf-8") as f:
|
|
79
|
+
app_config = json.load(f)
|
|
80
|
+
except Exception as exc: # noqa: BLE001
|
|
81
|
+
print(f"❌ Failed to load configuration: {exc}")
|
|
82
|
+
raise SystemExit(1)
|
|
83
|
+
|
|
84
|
+
if args.port:
|
|
85
|
+
app_config.setdefault("server", {}).update({"port": args.port})
|
|
86
|
+
print(f"🔧 Overriding port to {args.port}")
|
|
87
|
+
if args.host:
|
|
88
|
+
app_config.setdefault("server", {}).update({"host": args.host})
|
|
89
|
+
print(f"🔧 Overriding host to {args.host}")
|
|
90
|
+
|
|
91
|
+
# Strict protocol checks: forbid any form of mTLS over HTTP
|
|
92
|
+
# Work directly with server section (SimpleConfig format)
|
|
93
|
+
server_cfg = app_config.get("server", {})
|
|
94
|
+
proto = str(server_cfg.get("protocol", "http")).lower()
|
|
95
|
+
|
|
96
|
+
# Get certificates from server section (SimpleConfig format)
|
|
97
|
+
cert_file = server_cfg.get("cert_file")
|
|
98
|
+
key_file = server_cfg.get("key_file")
|
|
99
|
+
ca_cert_file = server_cfg.get("ca_cert_file")
|
|
100
|
+
|
|
101
|
+
transport = app_config.get("transport", {}) or {}
|
|
102
|
+
require_client_cert = bool(transport.get("verify_client") or (proto == "mtls"))
|
|
103
|
+
|
|
104
|
+
if proto == "http":
|
|
105
|
+
if require_client_cert:
|
|
106
|
+
raise SystemExit(
|
|
107
|
+
"CRITICAL CONFIG ERROR: mTLS (client certificate verification) cannot be used with HTTP. "
|
|
108
|
+
"Switch protocol to 'mtls' (or 'https' without client verification), and configure SSL certificates."
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if proto == "mtls":
|
|
112
|
+
if not (cert_file and key_file):
|
|
113
|
+
raise SystemExit(
|
|
114
|
+
"CRITICAL CONFIG ERROR: Protocol 'mtls' requires server.cert_file and server.key_file."
|
|
115
|
+
)
|
|
116
|
+
if not require_client_cert:
|
|
117
|
+
raise SystemExit(
|
|
118
|
+
"CRITICAL CONFIG ERROR: Protocol 'mtls' requires client certificate verification. "
|
|
119
|
+
"Set transport.verify_client=true."
|
|
120
|
+
)
|
|
121
|
+
if not ca_cert_file:
|
|
122
|
+
raise SystemExit(
|
|
123
|
+
"CRITICAL CONFIG ERROR: 'mtls' requires server.ca_cert_file."
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
app = create_app(
|
|
127
|
+
title="Full Application Example",
|
|
128
|
+
description="Complete MCP Proxy Adapter with all features",
|
|
129
|
+
version="1.0.0",
|
|
130
|
+
app_config=app_config,
|
|
131
|
+
config_path=str(cfg_path),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
port = int(app_config.get("server", {}).get("port", 8080))
|
|
135
|
+
host = app_config.get("server", {}).get("host", args.host)
|
|
136
|
+
|
|
137
|
+
print("🚀 Starting Full Application Example")
|
|
138
|
+
print(f"📋 Configuration: {cfg_path}")
|
|
139
|
+
print("============================================================")
|
|
140
|
+
|
|
141
|
+
# Register all commands
|
|
142
|
+
register_all_commands()
|
|
143
|
+
print(
|
|
144
|
+
f"📋 Registered commands: {', '.join(sorted(registry.get_all_commands().keys()))}"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
# Prepare server configuration for ServerEngine
|
|
148
|
+
server_config = {
|
|
149
|
+
"host": host,
|
|
150
|
+
"port": port,
|
|
151
|
+
"log_level": "info",
|
|
152
|
+
"reload": False,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
# Add SSL configuration from server section (SimpleConfig format)
|
|
156
|
+
cert = server_cfg.get("cert_file")
|
|
157
|
+
key = server_cfg.get("key_file")
|
|
158
|
+
ca = server_cfg.get("ca_cert_file")
|
|
159
|
+
verify_client = (server_cfg.get("protocol") == "mtls") or transport.get(
|
|
160
|
+
"verify_client", False
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if cert and key:
|
|
164
|
+
server_config["certfile"] = cert
|
|
165
|
+
server_config["keyfile"] = key
|
|
166
|
+
if ca:
|
|
167
|
+
server_config["ca_certs"] = ca
|
|
168
|
+
if verify_client:
|
|
169
|
+
server_config["verify_mode"] = 2 # ssl.CERT_REQUIRED
|
|
170
|
+
# Check hostname setting from server section
|
|
171
|
+
if server_cfg.get("check_hostname") is not None:
|
|
172
|
+
server_config["check_hostname"] = server_cfg["check_hostname"]
|
|
173
|
+
|
|
174
|
+
# Optional proxy registration - support both old (proxy_registration) and new (registration) formats
|
|
175
|
+
pr = {}
|
|
176
|
+
if isinstance(app_config, dict):
|
|
177
|
+
# Try new SimpleConfig format first (registration section)
|
|
178
|
+
registration = app_config.get("registration", {})
|
|
179
|
+
if registration and registration.get("enabled"):
|
|
180
|
+
pr = {
|
|
181
|
+
"enabled": True,
|
|
182
|
+
"proxy_url": f"{registration.get('protocol', 'http')}://{registration.get('host', 'localhost')}:{registration.get('port', 3005)}",
|
|
183
|
+
"server_id": registration.get("server_id")
|
|
184
|
+
or registration.get("server_name"),
|
|
185
|
+
"server_name": registration.get("server_name")
|
|
186
|
+
or registration.get("server_id"),
|
|
187
|
+
"auto_register_on_startup": registration.get("auto_on_startup", True),
|
|
188
|
+
"auto_unregister_on_shutdown": registration.get(
|
|
189
|
+
"auto_on_shutdown", True
|
|
190
|
+
),
|
|
191
|
+
"heartbeat": {
|
|
192
|
+
"enabled": True,
|
|
193
|
+
"interval": (
|
|
194
|
+
registration.get("heartbeat", {}).get("interval", 30)
|
|
195
|
+
if isinstance(registration.get("heartbeat"), dict)
|
|
196
|
+
else 30
|
|
197
|
+
),
|
|
198
|
+
},
|
|
199
|
+
}
|
|
200
|
+
# Fallback to old format (proxy_registration section)
|
|
201
|
+
elif app_config.get("proxy_registration"):
|
|
202
|
+
pr = app_config.get("proxy_registration", {})
|
|
203
|
+
# Also check proxy_client (SimpleConfig old format)
|
|
204
|
+
elif app_config.get("proxy_client", {}).get("enabled"):
|
|
205
|
+
pc = app_config.get("proxy_client", {})
|
|
206
|
+
pr = {
|
|
207
|
+
"enabled": True,
|
|
208
|
+
"proxy_url": f"{pc.get('protocol', 'http')}://{pc.get('host', 'localhost')}:{pc.get('port', 3005)}",
|
|
209
|
+
"server_id": pc.get("server_id") or pc.get("server_name"),
|
|
210
|
+
"server_name": pc.get("server_name") or pc.get("server_id"),
|
|
211
|
+
"auto_register_on_startup": (
|
|
212
|
+
pc.get("registration", {}).get("auto_on_startup", True)
|
|
213
|
+
if isinstance(pc.get("registration"), dict)
|
|
214
|
+
else True
|
|
215
|
+
),
|
|
216
|
+
"auto_unregister_on_shutdown": (
|
|
217
|
+
pc.get("registration", {}).get("auto_on_shutdown", True)
|
|
218
|
+
if isinstance(pc.get("registration"), dict)
|
|
219
|
+
else True
|
|
220
|
+
),
|
|
221
|
+
"heartbeat": pc.get("heartbeat", {}),
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
name = pr.get("server_id") or pr.get("server_name") or "mcp-adapter"
|
|
225
|
+
scheme = (
|
|
226
|
+
"https"
|
|
227
|
+
if str(app_config.get("server", {}).get("protocol", "http"))
|
|
228
|
+
in ("https", "mtls")
|
|
229
|
+
else "http"
|
|
230
|
+
)
|
|
231
|
+
advertised_host = (
|
|
232
|
+
app_config.get("server", {}).get("advertised_host") or "mcp-adapter"
|
|
233
|
+
)
|
|
234
|
+
advertised_url = f"{scheme}://{advertised_host}:{port}"
|
|
235
|
+
|
|
236
|
+
async def _run():
|
|
237
|
+
"""Run server with proxy registration and heartbeat."""
|
|
238
|
+
heartbeat_task = None
|
|
239
|
+
try:
|
|
240
|
+
if pr.get("enabled") and pr.get("proxy_url"):
|
|
241
|
+
pc = ProxyClient(pr["proxy_url"])
|
|
242
|
+
try:
|
|
243
|
+
await pc.register(
|
|
244
|
+
name=name,
|
|
245
|
+
url=advertised_url,
|
|
246
|
+
capabilities=["jsonrpc"],
|
|
247
|
+
metadata={},
|
|
248
|
+
)
|
|
249
|
+
print(f"✅ Registered on proxy as {name} -> {advertised_url}")
|
|
250
|
+
except Exception as exc: # noqa: BLE001
|
|
251
|
+
print(f"⚠️ Proxy registration failed: {exc}")
|
|
252
|
+
|
|
253
|
+
async def _hb():
|
|
254
|
+
interval = int((pr.get("heartbeat") or {}).get("interval", 15))
|
|
255
|
+
while True:
|
|
256
|
+
try:
|
|
257
|
+
await pc.heartbeat(name=name, url=advertised_url)
|
|
258
|
+
except Exception:
|
|
259
|
+
pass
|
|
260
|
+
await asyncio.sleep(max(2, interval))
|
|
261
|
+
|
|
262
|
+
heartbeat_task = asyncio.create_task(_hb())
|
|
263
|
+
|
|
264
|
+
# Use ServerEngine with hypercorn (via ServerEngineFactory)
|
|
265
|
+
engine = ServerEngineFactory.get_engine("hypercorn")
|
|
266
|
+
if not engine:
|
|
267
|
+
raise RuntimeError("Hypercorn engine not available")
|
|
268
|
+
|
|
269
|
+
# Run server using hypercorn engine
|
|
270
|
+
# Use create_task instead of run_server to avoid nested event loop
|
|
271
|
+
from hypercorn.asyncio import serve
|
|
272
|
+
from hypercorn.config import Config as HypercornConfig
|
|
273
|
+
|
|
274
|
+
hypercorn_config = HypercornConfig()
|
|
275
|
+
hypercorn_config.bind = [f"{host}:{port}"]
|
|
276
|
+
hypercorn_config.loglevel = "info"
|
|
277
|
+
|
|
278
|
+
# Add SSL configuration from server section (SimpleConfig format)
|
|
279
|
+
server_cfg = app_config.get("server", {})
|
|
280
|
+
cert = server_cfg.get("cert_file")
|
|
281
|
+
key = server_cfg.get("key_file")
|
|
282
|
+
ca = server_cfg.get("ca_cert_file")
|
|
283
|
+
verify_client = (server_cfg.get("protocol") == "mtls") or app_config.get(
|
|
284
|
+
"transport", {}
|
|
285
|
+
).get("verify_client", False)
|
|
286
|
+
|
|
287
|
+
if cert and key:
|
|
288
|
+
hypercorn_config.certfile = cert
|
|
289
|
+
hypercorn_config.keyfile = key
|
|
290
|
+
if ca:
|
|
291
|
+
hypercorn_config.ca_certs = ca
|
|
292
|
+
if verify_client:
|
|
293
|
+
hypercorn_config.verify_mode = 2 # ssl.CERT_REQUIRED
|
|
294
|
+
|
|
295
|
+
await serve(app, hypercorn_config)
|
|
296
|
+
finally:
|
|
297
|
+
if heartbeat_task:
|
|
298
|
+
heartbeat_task.cancel()
|
|
299
|
+
if pr.get("enabled") and pr.get("proxy_url"):
|
|
300
|
+
try:
|
|
301
|
+
pc = ProxyClient(pr["proxy_url"])
|
|
302
|
+
await pc.unregister(name)
|
|
303
|
+
print(f"🛑 Unregistered from proxy: {name}")
|
|
304
|
+
except Exception:
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
asyncio.run(_run())
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
if __name__ == "__main__":
|
|
311
|
+
main()
|