mcp-proxy-adapter 6.9.43__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_proxy_adapter/__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 +355 -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 +266 -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 +35 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +74 -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 +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 +388 -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 +116 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +100 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +380 -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 +190 -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 +13 -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 +264 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +81 -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 +313 -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.43.dist-info/METADATA +739 -0
- mcp_proxy_adapter-6.9.43.dist-info/RECORD +242 -0
- mcp_proxy_adapter-6.9.43.dist-info/WHEEL +5 -0
- mcp_proxy_adapter-6.9.43.dist-info/entry_points.txt +12 -0
- mcp_proxy_adapter-6.9.43.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
mTLS Server implementation using built-in http.server.
|
|
4
|
+
|
|
5
|
+
Author: Vasiliy Zdanovskiy
|
|
6
|
+
email: vasilyvz@gmail.com
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import threading
|
|
10
|
+
import ssl
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
14
|
+
from typing import Optional, Dict, Any
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class mTLSHandler(BaseHTTPRequestHandler):
|
|
21
|
+
"""Handler for mTLS connections."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, *args, main_app=None, **kwargs):
|
|
24
|
+
self.main_app = main_app
|
|
25
|
+
super().__init__(*args, **kwargs)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _forward_to_main_app(
|
|
31
|
+
self,
|
|
32
|
+
method: str,
|
|
33
|
+
path: str,
|
|
34
|
+
client_cert: Optional[Dict],
|
|
35
|
+
post_data: Optional[bytes] = None,
|
|
36
|
+
) -> Dict[str, Any]:
|
|
37
|
+
"""Forward request to main FastAPI application."""
|
|
38
|
+
try:
|
|
39
|
+
# This is a simplified forwarding - in real implementation
|
|
40
|
+
# you would use httpx or similar to make internal HTTP calls
|
|
41
|
+
# to the main FastAPI app running on different port
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
"status": "ok",
|
|
45
|
+
"message": f"mTLS {method} forwarded to main app",
|
|
46
|
+
"client_cert": client_cert,
|
|
47
|
+
"path": path,
|
|
48
|
+
"forwarded": True,
|
|
49
|
+
}
|
|
50
|
+
except Exception as e:
|
|
51
|
+
get_global_logger().error(f"Error forwarding to main app: {e}")
|
|
52
|
+
return {
|
|
53
|
+
"status": "error",
|
|
54
|
+
"message": f"Forwarding failed: {e}",
|
|
55
|
+
"client_cert": client_cert,
|
|
56
|
+
"path": path,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class mTLSServer:
|
|
61
|
+
"""mTLS Server using built-in http.server."""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
host: str = "127.0.0.1",
|
|
66
|
+
port: int = 8443,
|
|
67
|
+
cert_file: str = None,
|
|
68
|
+
key_file: str = None,
|
|
69
|
+
ca_cert_file: str = None,
|
|
70
|
+
main_app=None,
|
|
71
|
+
):
|
|
72
|
+
"""
|
|
73
|
+
Initialize mTLS server.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
host: Server host
|
|
77
|
+
port: Server port
|
|
78
|
+
cert_file: Server certificate file
|
|
79
|
+
key_file: Server private key file
|
|
80
|
+
ca_cert_file: CA certificate file for client verification
|
|
81
|
+
main_app: Main FastAPI application for forwarding requests
|
|
82
|
+
"""
|
|
83
|
+
self.host = host
|
|
84
|
+
self.port = port
|
|
85
|
+
self.cert_file = cert_file
|
|
86
|
+
self.key_file = key_file
|
|
87
|
+
self.ca_cert_file = ca_cert_file
|
|
88
|
+
self.main_app = main_app
|
|
89
|
+
|
|
90
|
+
self.server: Optional[HTTPServer] = None
|
|
91
|
+
self.server_thread: Optional[threading.Thread] = None
|
|
92
|
+
self.running = False
|
|
93
|
+
|
|
94
|
+
get_global_logger().info(f"mTLS Server initialized: {host}:{port}")
|
|
95
|
+
|
|
96
|
+
def _create_handler(self):
|
|
97
|
+
"""Create handler with main app reference."""
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
return handler
|
|
101
|
+
|
|
102
|
+
def start(self) -> bool:
|
|
103
|
+
"""Start mTLS server in separate thread."""
|
|
104
|
+
try:
|
|
105
|
+
# Check if certificate files exist
|
|
106
|
+
if not os.path.exists(self.cert_file):
|
|
107
|
+
get_global_logger().error(f"Certificate file not found: {self.cert_file}")
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
if not os.path.exists(self.key_file):
|
|
111
|
+
get_global_logger().error(f"Key file not found: {self.key_file}")
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
if not os.path.exists(self.ca_cert_file):
|
|
115
|
+
get_global_logger().error(
|
|
116
|
+
f"CA certificate file not found: {self.ca_cert_file}"
|
|
117
|
+
)
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
# Create server
|
|
121
|
+
handler_class = self._create_handler()
|
|
122
|
+
self.server = HTTPServer((self.host, self.port), handler_class)
|
|
123
|
+
|
|
124
|
+
# Configure SSL context
|
|
125
|
+
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
126
|
+
context.load_cert_chain(self.cert_file, self.key_file)
|
|
127
|
+
context.load_verify_locations(self.ca_cert_file)
|
|
128
|
+
context.verify_mode = ssl.CERT_REQUIRED
|
|
129
|
+
|
|
130
|
+
# Wrap socket with SSL
|
|
131
|
+
self.server.socket = context.wrap_socket(
|
|
132
|
+
self.server.socket, server_side=True
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Start server in separate thread
|
|
136
|
+
self.server_thread = threading.Thread(
|
|
137
|
+
target=self._run_server, daemon=True
|
|
138
|
+
)
|
|
139
|
+
self.server_thread.start()
|
|
140
|
+
|
|
141
|
+
self.running = True
|
|
142
|
+
get_global_logger().info(
|
|
143
|
+
f"✅ mTLS Server started on https://{self.host}:{self.port}"
|
|
144
|
+
)
|
|
145
|
+
return True
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
get_global_logger().error(f"Failed to start mTLS server: {e}")
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Protocol management module for MCP Proxy Adapter.
|
|
3
|
+
|
|
4
|
+
This module provides functionality for managing and validating protocol configurations,
|
|
5
|
+
including HTTP, HTTPS, and MTLS protocols with their respective ports.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import ssl
|
|
9
|
+
from urllib.parse import urlparse
|
|
10
|
+
from typing import Dict, List, Any, Optional
|
|
11
|
+
|
|
12
|
+
from mcp_proxy_adapter.config import config
|
|
13
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ProtocolManager:
|
|
17
|
+
"""
|
|
18
|
+
Manages protocol configurations and validates protocol access.
|
|
19
|
+
|
|
20
|
+
This class handles the validation of allowed protocols and their associated ports,
|
|
21
|
+
ensuring that only configured protocols are accessible.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, app_config: Optional[Dict] = None):
|
|
25
|
+
"""
|
|
26
|
+
Initialize the protocol manager.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
app_config: Application configuration dictionary (optional)
|
|
30
|
+
"""
|
|
31
|
+
self.app_config = app_config
|
|
32
|
+
self._load_config()
|
|
33
|
+
|
|
34
|
+
def _load_config(self):
|
|
35
|
+
"""Load protocol configuration from config."""
|
|
36
|
+
# Use provided config or fallback to global config; normalize types
|
|
37
|
+
current_config = (
|
|
38
|
+
self.app_config if self.app_config is not None else config.get_all()
|
|
39
|
+
)
|
|
40
|
+
get_global_logger().debug(
|
|
41
|
+
f"ProtocolManager._load_config - current_config type: {type(current_config)}"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if not hasattr(current_config, "get"):
|
|
45
|
+
# Not a dict-like config, fallback to global
|
|
46
|
+
get_global_logger().debug(
|
|
47
|
+
f"ProtocolManager._load_config - current_config is not dict-like, falling back to global config"
|
|
48
|
+
)
|
|
49
|
+
current_config = config.get_all()
|
|
50
|
+
|
|
51
|
+
get_global_logger().debug(
|
|
52
|
+
f"ProtocolManager._load_config - final current_config type: {type(current_config)}"
|
|
53
|
+
)
|
|
54
|
+
if hasattr(current_config, "get"):
|
|
55
|
+
get_global_logger().debug(
|
|
56
|
+
f"ProtocolManager._load_config - current_config keys: {list(current_config.keys()) if hasattr(current_config, 'keys') else 'no keys'}"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Get server protocol configuration (new simplified structure)
|
|
60
|
+
get_global_logger().debug(f"ProtocolManager._load_config - before getting server protocol")
|
|
61
|
+
try:
|
|
62
|
+
server_config = current_config.get("server", {})
|
|
63
|
+
server_protocol = server_config.get("protocol", "http")
|
|
64
|
+
get_global_logger().debug(f"ProtocolManager._load_config - server protocol: {server_protocol}")
|
|
65
|
+
|
|
66
|
+
# Set allowed protocols based on server protocol
|
|
67
|
+
if server_protocol == "http":
|
|
68
|
+
self.allowed_protocols = ["http"]
|
|
69
|
+
elif server_protocol == "https":
|
|
70
|
+
self.allowed_protocols = ["https"]
|
|
71
|
+
elif server_protocol == "mtls":
|
|
72
|
+
self.allowed_protocols = ["mtls", "https"] # mTLS also supports HTTPS
|
|
73
|
+
else:
|
|
74
|
+
# Fallback to HTTP
|
|
75
|
+
self.allowed_protocols = ["http"]
|
|
76
|
+
get_global_logger().warning(f"Unknown server protocol '{server_protocol}', defaulting to HTTP")
|
|
77
|
+
|
|
78
|
+
get_global_logger().debug(f"ProtocolManager._load_config - allowed protocols: {self.allowed_protocols}")
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
get_global_logger().debug(f"ProtocolManager._load_config - ERROR getting server protocol: {e}")
|
|
82
|
+
# Fallback to HTTP
|
|
83
|
+
self.allowed_protocols = ["http"]
|
|
84
|
+
|
|
85
|
+
# Protocol management is always enabled in new structure
|
|
86
|
+
self.enabled = True
|
|
87
|
+
|
|
88
|
+
get_global_logger().debug(
|
|
89
|
+
f"Protocol manager loaded config: enabled={self.enabled}, allowed_protocols={self.allowed_protocols}"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def is_protocol_allowed(self, protocol: str) -> bool:
|
|
96
|
+
"""
|
|
97
|
+
Check if a protocol is allowed based on configuration.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
protocol: Protocol name (http, https, mtls)
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
True if protocol is allowed, False otherwise
|
|
104
|
+
"""
|
|
105
|
+
get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - protocol: {protocol}")
|
|
106
|
+
get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - enabled: {self.enabled}")
|
|
107
|
+
get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - allowed_protocols: {self.allowed_protocols}")
|
|
108
|
+
|
|
109
|
+
if not self.enabled:
|
|
110
|
+
get_global_logger().debug("✅ ProtocolManager.is_protocol_allowed - Protocol management is disabled, allowing all protocols")
|
|
111
|
+
return True
|
|
112
|
+
|
|
113
|
+
protocol_lower = protocol.lower()
|
|
114
|
+
is_allowed = protocol_lower in self.allowed_protocols
|
|
115
|
+
|
|
116
|
+
get_global_logger().debug(f"🔍 ProtocolManager.is_protocol_allowed - Protocol '{protocol}' allowed: {is_allowed}")
|
|
117
|
+
return is_allowed
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def get_protocol_config(self, protocol: str) -> Dict:
|
|
122
|
+
"""
|
|
123
|
+
Get full configuration for a specific protocol.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
protocol: Protocol name (http, https, mtls)
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Protocol configuration dictionary
|
|
130
|
+
"""
|
|
131
|
+
protocol_lower = protocol.lower()
|
|
132
|
+
cfg = self.protocols_config.get(protocol_lower, {})
|
|
133
|
+
# Ensure dict type
|
|
134
|
+
if isinstance(cfg, dict):
|
|
135
|
+
try:
|
|
136
|
+
return cfg.copy()
|
|
137
|
+
except Exception:
|
|
138
|
+
return {}
|
|
139
|
+
return {}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def get_ssl_context_for_protocol(self, protocol: str) -> Optional[ssl.SSLContext]:
|
|
143
|
+
"""
|
|
144
|
+
Get SSL context for HTTPS or MTLS protocol.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
protocol: Protocol name (https, mtls)
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
SSL context if protocol requires SSL, None otherwise
|
|
151
|
+
"""
|
|
152
|
+
if protocol.lower() not in ["https", "mtls"]:
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
# Use provided config or fallback to global config
|
|
156
|
+
current_config = (
|
|
157
|
+
self.app_config if self.app_config is not None else config.get_all()
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
# Get SSL configuration
|
|
161
|
+
ssl_config = self._get_ssl_config(current_config)
|
|
162
|
+
|
|
163
|
+
if not ssl_config.get("enabled", False):
|
|
164
|
+
get_global_logger().warning(
|
|
165
|
+
f"SSL required for protocol '{protocol}' but SSL is disabled"
|
|
166
|
+
)
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
cert_file = ssl_config.get("cert_file")
|
|
170
|
+
key_file = ssl_config.get("key_file")
|
|
171
|
+
|
|
172
|
+
if not cert_file or not key_file:
|
|
173
|
+
get_global_logger().warning(
|
|
174
|
+
f"SSL required for protocol '{protocol}' but certificate files not configured"
|
|
175
|
+
)
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
from mcp_proxy_adapter.core.ssl_utils import SSLUtils
|
|
180
|
+
|
|
181
|
+
ssl_context = SSLUtils.create_ssl_context(
|
|
182
|
+
cert_file=cert_file,
|
|
183
|
+
key_file=key_file,
|
|
184
|
+
ca_cert=ssl_config.get("ca_cert"),
|
|
185
|
+
verify_client=protocol.lower() == "mtls"
|
|
186
|
+
or ssl_config.get("verify_client", False),
|
|
187
|
+
cipher_suites=ssl_config.get("cipher_suites", []),
|
|
188
|
+
min_tls_version=ssl_config.get("min_tls_version", "1.2"),
|
|
189
|
+
max_tls_version=ssl_config.get("max_tls_version", "1.3"),
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
get_global_logger().info(f"SSL context created for protocol '{protocol}'")
|
|
193
|
+
return ssl_context
|
|
194
|
+
|
|
195
|
+
except Exception as e:
|
|
196
|
+
get_global_logger().error(f"Failed to create SSL context for protocol '{protocol}': {e}")
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
def _get_ssl_config(self, current_config: Dict) -> Dict:
|
|
200
|
+
"""
|
|
201
|
+
Get SSL configuration from config.
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
current_config: Current configuration dictionary
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
SSL configuration dictionary
|
|
208
|
+
"""
|
|
209
|
+
# Try security framework SSL config first
|
|
210
|
+
security_config = current_config.get("security", {})
|
|
211
|
+
ssl_config = security_config.get("ssl", {})
|
|
212
|
+
|
|
213
|
+
if ssl_config.get("enabled", False):
|
|
214
|
+
get_global_logger().debug("Using security.ssl configuration")
|
|
215
|
+
return ssl_config
|
|
216
|
+
|
|
217
|
+
# Fallback to legacy SSL config
|
|
218
|
+
legacy_ssl_config = current_config.get("ssl", {})
|
|
219
|
+
if legacy_ssl_config.get("enabled", False):
|
|
220
|
+
get_global_logger().debug("Using legacy ssl configuration")
|
|
221
|
+
return legacy_ssl_config
|
|
222
|
+
|
|
223
|
+
# Return empty config if SSL is disabled
|
|
224
|
+
return {"enabled": False}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# Global protocol manager instance - will be updated with config when needed
|
|
230
|
+
protocol_manager = None
|
|
231
|
+
|
|
232
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Proxy registration package for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .proxy_registration_manager import ProxyRegistrationManager, ProxyRegistrationError
|
|
9
|
+
from .auth_manager import AuthManager
|
|
10
|
+
from .ssl_manager import SSLManager
|
|
11
|
+
from .registration_client import RegistrationClient
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"ProxyRegistrationManager",
|
|
15
|
+
"ProxyRegistrationError",
|
|
16
|
+
"AuthManager",
|
|
17
|
+
"SSLManager",
|
|
18
|
+
"RegistrationClient",
|
|
19
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Authentication management for proxy registration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Any
|
|
9
|
+
|
|
10
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AuthManager:
|
|
14
|
+
"""Manager for authentication in proxy registration."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, client_security, registration_config: Dict[str, Any]):
|
|
17
|
+
"""
|
|
18
|
+
Initialize authentication manager.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
client_security: Client security manager instance
|
|
22
|
+
registration_config: Registration configuration
|
|
23
|
+
"""
|
|
24
|
+
self.client_security = client_security
|
|
25
|
+
self.registration_config = registration_config
|
|
26
|
+
self.logger = get_global_logger()
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Main proxy registration manager for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import time
|
|
9
|
+
from typing import Dict, Any
|
|
10
|
+
|
|
11
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
12
|
+
from mcp_proxy_adapter.core.client_security import create_client_security_manager
|
|
13
|
+
from .registration_client import RegistrationClient
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ProxyRegistrationError(Exception):
|
|
17
|
+
"""Exception raised when proxy registration fails."""
|
|
18
|
+
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ProxyRegistrationManager:
|
|
23
|
+
"""
|
|
24
|
+
Manager for proxy registration functionality with security framework integration.
|
|
25
|
+
|
|
26
|
+
Handles automatic registration and unregistration of the server
|
|
27
|
+
with the MCP proxy server using secure authentication methods.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, config: Dict[str, Any]):
|
|
31
|
+
"""
|
|
32
|
+
Initialize the proxy registration manager.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
config: Application configuration
|
|
36
|
+
"""
|
|
37
|
+
self.config = config
|
|
38
|
+
self.logger = get_global_logger()
|
|
39
|
+
|
|
40
|
+
# Get registration configuration
|
|
41
|
+
self.registration_config = config.get("proxy_registration", {})
|
|
42
|
+
|
|
43
|
+
# Initialize client security
|
|
44
|
+
self.client_security = create_client_security_manager(config)
|
|
45
|
+
|
|
46
|
+
# Registration state
|
|
47
|
+
self.proxy_url = self.registration_config.get("proxy_url")
|
|
48
|
+
self.server_url = None
|
|
49
|
+
self.registered = False
|
|
50
|
+
self.registration_time = None
|
|
51
|
+
|
|
52
|
+
# Initialize registration client
|
|
53
|
+
self.registration_client = RegistrationClient(
|
|
54
|
+
self.client_security, self.registration_config, config, self.proxy_url
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def is_enabled(self) -> bool:
|
|
58
|
+
"""
|
|
59
|
+
Check if proxy registration is enabled.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
True if enabled, False otherwise
|
|
63
|
+
"""
|
|
64
|
+
return self.registration_config.get("enabled", False)
|
|
65
|
+
|
|
66
|
+
async def register(self) -> bool:
|
|
67
|
+
"""
|
|
68
|
+
Register server with proxy.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
True if registration successful, False otherwise
|
|
72
|
+
"""
|
|
73
|
+
if not self.is_enabled():
|
|
74
|
+
self.logger.info("Proxy registration is disabled")
|
|
75
|
+
return True
|
|
76
|
+
|
|
77
|
+
if not self.server_url:
|
|
78
|
+
self.logger.error("Server URL not set for registration")
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
if not self.proxy_url:
|
|
82
|
+
self.logger.error("Proxy URL not configured")
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
self.logger.info(f"Registering with proxy: {self.proxy_url}")
|
|
87
|
+
|
|
88
|
+
success = await self.registration_client.register(self.server_url)
|
|
89
|
+
|
|
90
|
+
if success:
|
|
91
|
+
self.registered = True
|
|
92
|
+
self.registration_time = time.time()
|
|
93
|
+
self.logger.info("✅ Proxy registration completed successfully")
|
|
94
|
+
else:
|
|
95
|
+
self.logger.error("❌ Proxy registration failed")
|
|
96
|
+
|
|
97
|
+
return success
|
|
98
|
+
|
|
99
|
+
except Exception as e:
|
|
100
|
+
self.logger.error(f"Registration error: {e}")
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
async def unregister(self) -> bool:
|
|
104
|
+
"""
|
|
105
|
+
Unregister server from proxy.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
True if unregistration successful, False otherwise
|
|
109
|
+
"""
|
|
110
|
+
if not self.is_enabled():
|
|
111
|
+
self.logger.info("Proxy registration is disabled")
|
|
112
|
+
return True
|
|
113
|
+
|
|
114
|
+
if not self.registered:
|
|
115
|
+
self.logger.info("Server not registered, skipping unregistration")
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
self.logger.info("Unregistering from proxy")
|
|
120
|
+
|
|
121
|
+
success = await self.registration_client.unregister()
|
|
122
|
+
|
|
123
|
+
if success:
|
|
124
|
+
self.registered = False
|
|
125
|
+
self.registration_time = None
|
|
126
|
+
self.logger.info("✅ Proxy unregistration completed successfully")
|
|
127
|
+
else:
|
|
128
|
+
self.logger.warning("⚠️ Proxy unregistration failed")
|
|
129
|
+
|
|
130
|
+
return success
|
|
131
|
+
|
|
132
|
+
except Exception as e:
|
|
133
|
+
self.logger.error(f"Unregistration error: {e}")
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
def set_server_url(self, server_url: str) -> None:
|
|
137
|
+
"""
|
|
138
|
+
Set server URL for registration.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
server_url: Server URL to register
|
|
142
|
+
"""
|
|
143
|
+
self.server_url = server_url
|
|
144
|
+
self.logger.info(f"Server URL set: {server_url}")
|
|
145
|
+
|
|
146
|
+
def get_registration_status(self) -> Dict[str, Any]:
|
|
147
|
+
"""
|
|
148
|
+
Get current registration status.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Dictionary with registration status information
|
|
152
|
+
"""
|
|
153
|
+
return {
|
|
154
|
+
"enabled": self.is_enabled(),
|
|
155
|
+
"registered": self.registered,
|
|
156
|
+
"proxy_url": self.proxy_url,
|
|
157
|
+
"server_url": self.server_url,
|
|
158
|
+
"registration_time": self.registration_time,
|
|
159
|
+
"client_security_available": self.client_security is not None,
|
|
160
|
+
}
|