mcp-proxy-adapter 6.9.28__py3-none-any.whl → 6.9.30__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +10 -0
- mcp_proxy_adapter/__main__.py +8 -21
- mcp_proxy_adapter/api/app.py +10 -913
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +243 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_manager.py +166 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +78 -199
- mcp_proxy_adapter/api/middleware/__init__.py +1 -44
- mcp_proxy_adapter/api/middleware/base.py +0 -42
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +0 -85
- mcp_proxy_adapter/api/middleware/error_handling.py +1 -127
- mcp_proxy_adapter/api/middleware/factory.py +0 -94
- mcp_proxy_adapter/api/middleware/logging.py +0 -112
- mcp_proxy_adapter/api/middleware/performance.py +0 -35
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +2 -98
- mcp_proxy_adapter/api/middleware/transport_middleware.py +0 -37
- mcp_proxy_adapter/api/middleware/unified_security.py +10 -10
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +0 -118
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +0 -61
- mcp_proxy_adapter/api/tool_integration.py +0 -117
- mcp_proxy_adapter/api/tools.py +0 -46
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +21 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +36 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +128 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +324 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client.py +406 -0
- mcp_proxy_adapter/client/proxy.py +45 -0
- mcp_proxy_adapter/commands/__init__.py +44 -28
- mcp_proxy_adapter/commands/auth_validation_command.py +7 -344
- mcp_proxy_adapter/commands/base.py +19 -43
- mcp_proxy_adapter/commands/builtin_commands.py +0 -75
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +58 -928
- mcp_proxy_adapter/commands/cert_monitor_command.py +0 -88
- mcp_proxy_adapter/commands/certificate_management_command.py +0 -45
- mcp_proxy_adapter/commands/command_registry.py +172 -904
- mcp_proxy_adapter/commands/config_command.py +0 -28
- mcp_proxy_adapter/commands/dependency_container.py +1 -70
- mcp_proxy_adapter/commands/dependency_manager.py +0 -128
- mcp_proxy_adapter/commands/echo_command.py +0 -34
- mcp_proxy_adapter/commands/health_command.py +0 -3
- mcp_proxy_adapter/commands/help_command.py +0 -159
- mcp_proxy_adapter/commands/hooks.py +0 -137
- mcp_proxy_adapter/commands/key_management_command.py +0 -25
- mcp_proxy_adapter/commands/load_command.py +7 -78
- mcp_proxy_adapter/commands/plugins_command.py +0 -16
- mcp_proxy_adapter/commands/protocol_management_command.py +0 -28
- mcp_proxy_adapter/commands/proxy_registration_command.py +0 -88
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +0 -43
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +0 -80
- mcp_proxy_adapter/commands/result.py +25 -77
- mcp_proxy_adapter/commands/role_test_command.py +0 -44
- mcp_proxy_adapter/commands/roles_management_command.py +0 -199
- mcp_proxy_adapter/commands/security_command.py +0 -30
- mcp_proxy_adapter/commands/settings_command.py +0 -68
- mcp_proxy_adapter/commands/ssl_setup_command.py +0 -42
- mcp_proxy_adapter/commands/token_management_command.py +0 -1
- mcp_proxy_adapter/commands/transport_management_command.py +0 -20
- mcp_proxy_adapter/commands/unload_command.py +0 -71
- mcp_proxy_adapter/config.py +15 -626
- mcp_proxy_adapter/core/__init__.py +5 -39
- mcp_proxy_adapter/core/app_factory.py +14 -36
- mcp_proxy_adapter/core/app_runner.py +0 -27
- mcp_proxy_adapter/core/auth_validator.py +1 -93
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +371 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +183 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +110 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +70 -0
- mcp_proxy_adapter/core/certificate_utils.py +64 -903
- mcp_proxy_adapter/core/client.py +10 -9
- mcp_proxy_adapter/core/client_manager.py +0 -19
- mcp_proxy_adapter/core/client_security.py +0 -2
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +195 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +112 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +50 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +96 -0
- mcp_proxy_adapter/core/config_converter.py +0 -186
- mcp_proxy_adapter/core/config_validator.py +96 -1238
- mcp_proxy_adapter/core/errors.py +7 -42
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +2 -22
- mcp_proxy_adapter/core/mtls_asgi.py +0 -20
- mcp_proxy_adapter/core/mtls_asgi_app.py +0 -12
- mcp_proxy_adapter/core/mtls_proxy.py +0 -80
- mcp_proxy_adapter/core/mtls_server.py +3 -173
- mcp_proxy_adapter/core/protocol_manager.py +1 -191
- mcp_proxy_adapter/core/proxy/__init__.py +22 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +27 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +137 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +60 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +0 -1
- mcp_proxy_adapter/core/proxy_registration.py +36 -913
- mcp_proxy_adapter/core/role_utils.py +0 -308
- mcp_proxy_adapter/core/security_adapter.py +1 -36
- mcp_proxy_adapter/core/security_factory.py +1 -150
- mcp_proxy_adapter/core/security_integration.py +0 -33
- mcp_proxy_adapter/core/server_adapter.py +1 -40
- mcp_proxy_adapter/core/server_engine.py +2 -173
- mcp_proxy_adapter/core/settings.py +0 -127
- mcp_proxy_adapter/core/signal_handler.py +0 -65
- mcp_proxy_adapter/core/ssl_utils.py +19 -137
- mcp_proxy_adapter/core/transport_manager.py +0 -151
- mcp_proxy_adapter/core/unified_config_adapter.py +1 -193
- mcp_proxy_adapter/core/utils.py +1 -182
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +211 -0
- mcp_proxy_adapter/core/validation/file_validator.py +73 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +191 -0
- mcp_proxy_adapter/core/validation/security_validator.py +58 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +33 -652
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +0 -23
- mcp_proxy_adapter/examples/check_config.py +0 -2
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/config_builder.py +13 -2
- mcp_proxy_adapter/examples/config_cli.py +0 -1
- mcp_proxy_adapter/examples/create_test_configs.py +0 -46
- mcp_proxy_adapter/examples/debug_request_state.py +0 -1
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -47
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -45
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +0 -7
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +0 -2
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -59
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -54
- mcp_proxy_adapter/examples/full_application/main.py +186 -150
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +0 -107
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +0 -24
- mcp_proxy_adapter/examples/full_application/test_server.py +0 -58
- mcp_proxy_adapter/examples/generate_config.py +65 -11
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +0 -2
- mcp_proxy_adapter/examples/run_full_test_suite.py +0 -29
- mcp_proxy_adapter/examples/run_proxy_server.py +31 -71
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -27
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +24 -1075
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +133 -1425
- mcp_proxy_adapter/examples/test_config.py +0 -3
- mcp_proxy_adapter/examples/test_config_builder.py +25 -405
- mcp_proxy_adapter/examples/test_examples.py +0 -1
- mcp_proxy_adapter/examples/test_framework_complete.py +0 -2
- mcp_proxy_adapter/examples/test_mcp_server.py +0 -1
- mcp_proxy_adapter/examples/test_protocol_examples.py +0 -1
- mcp_proxy_adapter/examples/universal_client.py +0 -6
- mcp_proxy_adapter/examples/update_config_certificates.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +0 -187
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +70 -62
- mcp_proxy_adapter/openapi.py +0 -22
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.9.30.dist-info/RECORD +235 -0
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/entry_points.txt +1 -1
- mcp_proxy_adapter-6.9.28.dist-info/RECORD +0 -149
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.28.dist-info → mcp_proxy_adapter-6.9.30.dist-info}/top_level.txt +0 -0
|
@@ -14,6 +14,8 @@ from abc import ABC, abstractmethod
|
|
|
14
14
|
from typing import Dict, Any, Optional
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
|
|
17
|
+
from .logging import get_global_logger
|
|
18
|
+
|
|
17
19
|
logger = logging.getLogger(__name__)
|
|
18
20
|
|
|
19
21
|
|
|
@@ -41,38 +43,10 @@ class ServerEngine(ABC):
|
|
|
41
43
|
pass
|
|
42
44
|
|
|
43
45
|
@abstractmethod
|
|
44
|
-
def get_config_schema(self) -> Dict[str, Any]:
|
|
45
|
-
"""
|
|
46
|
-
Get configuration schema for this server engine.
|
|
47
|
-
|
|
48
|
-
Returns:
|
|
49
|
-
Dictionary describing the configuration options
|
|
50
|
-
"""
|
|
51
|
-
pass
|
|
52
46
|
|
|
53
47
|
@abstractmethod
|
|
54
|
-
def validate_config(self, config: Dict[str, Any]) -> bool:
|
|
55
|
-
"""
|
|
56
|
-
Validate configuration for this server engine.
|
|
57
|
-
|
|
58
|
-
Args:
|
|
59
|
-
config: Configuration dictionary
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
True if configuration is valid, False otherwise
|
|
63
|
-
"""
|
|
64
|
-
pass
|
|
65
48
|
|
|
66
49
|
@abstractmethod
|
|
67
|
-
def run_server(self, app: Any, config: Dict[str, Any]) -> None:
|
|
68
|
-
"""
|
|
69
|
-
Run the server with the given configuration.
|
|
70
|
-
|
|
71
|
-
Args:
|
|
72
|
-
app: ASGI application
|
|
73
|
-
config: Server configuration
|
|
74
|
-
"""
|
|
75
|
-
pass
|
|
76
50
|
|
|
77
51
|
|
|
78
52
|
class HypercornEngine(ServerEngine):
|
|
@@ -96,120 +70,8 @@ class HypercornEngine(ServerEngine):
|
|
|
96
70
|
"reload": True,
|
|
97
71
|
}
|
|
98
72
|
|
|
99
|
-
def get_config_schema(self) -> Dict[str, Any]:
|
|
100
|
-
return {
|
|
101
|
-
"host": {"type": "string", "default": "127.0.0.1"},
|
|
102
|
-
"port": {"type": "integer", "default": 8000},
|
|
103
|
-
"log_level": {"type": "string", "default": "INFO"},
|
|
104
|
-
"certfile": {"type": "string", "optional": True},
|
|
105
|
-
"keyfile": {"type": "string", "optional": True},
|
|
106
|
-
"ca_certs": {"type": "string", "optional": True},
|
|
107
|
-
"verify_mode": {"type": "string", "optional": True},
|
|
108
|
-
"reload": {"type": "boolean", "default": False},
|
|
109
|
-
"workers": {"type": "integer", "optional": True},
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
def validate_config(self, config: Dict[str, Any]) -> bool:
|
|
113
|
-
"""Validate hypercorn configuration."""
|
|
114
|
-
required_fields = ["host", "port"]
|
|
115
|
-
|
|
116
|
-
for field in required_fields:
|
|
117
|
-
if field not in config:
|
|
118
|
-
get_global_logger().error(f"Missing required field: {field}")
|
|
119
|
-
return False
|
|
120
73
|
|
|
121
|
-
# Validate SSL files exist if specified
|
|
122
|
-
ssl_files = ["certfile", "keyfile", "ca_certs"]
|
|
123
|
-
for ssl_file in ssl_files:
|
|
124
|
-
if ssl_file in config and config[ssl_file]:
|
|
125
|
-
if not Path(config[ssl_file]).exists():
|
|
126
|
-
get_global_logger().error(f"SSL file not found: {config[ssl_file]}")
|
|
127
|
-
return False
|
|
128
74
|
|
|
129
|
-
return True
|
|
130
|
-
|
|
131
|
-
def run_server(self, app: Any, config: Dict[str, Any]) -> None:
|
|
132
|
-
"""Run hypercorn server."""
|
|
133
|
-
try:
|
|
134
|
-
import hypercorn.asyncio
|
|
135
|
-
import asyncio
|
|
136
|
-
|
|
137
|
-
# Prepare hypercorn config
|
|
138
|
-
hypercorn_config = {
|
|
139
|
-
"bind": f"{config.get('host', '127.0.0.1')}:{config.get('port', 8000)}",
|
|
140
|
-
"log_level": config.get("log_level", "INFO"),
|
|
141
|
-
"reload": config.get("reload", False),
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
# Add SSL configuration if provided
|
|
145
|
-
get_global_logger().info(f"🔍 DEBUG: Input config keys: {list(config.keys())}")
|
|
146
|
-
get_global_logger().info(
|
|
147
|
-
f"🔍 DEBUG: Input config certfile: {config.get('certfile', 'NOT_FOUND')}"
|
|
148
|
-
)
|
|
149
|
-
get_global_logger().info(
|
|
150
|
-
f"🔍 DEBUG: Input config keyfile: {config.get('keyfile', 'NOT_FOUND')}"
|
|
151
|
-
)
|
|
152
|
-
get_global_logger().info(
|
|
153
|
-
f"🔍 DEBUG: Input config ca_certs: {config.get('ca_certs', 'NOT_FOUND')}"
|
|
154
|
-
)
|
|
155
|
-
get_global_logger().info(
|
|
156
|
-
f"🔍 DEBUG: Input config verify_mode: {config.get('verify_mode', 'NOT_FOUND')}"
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
if "certfile" in config and config["certfile"]:
|
|
160
|
-
hypercorn_config["certfile"] = config["certfile"]
|
|
161
|
-
if "keyfile" in config and config["keyfile"]:
|
|
162
|
-
hypercorn_config["keyfile"] = config["keyfile"]
|
|
163
|
-
if "ca_certs" in config and config["ca_certs"]:
|
|
164
|
-
hypercorn_config["ca_certs"] = config["ca_certs"]
|
|
165
|
-
if "verify_mode" in config and config["verify_mode"]:
|
|
166
|
-
# Convert verify_mode string to SSL constant
|
|
167
|
-
verify_mode_str = config["verify_mode"]
|
|
168
|
-
if verify_mode_str == "CERT_NONE":
|
|
169
|
-
import ssl
|
|
170
|
-
|
|
171
|
-
hypercorn_config["verify_mode"] = ssl.CERT_NONE
|
|
172
|
-
elif verify_mode_str == "CERT_REQUIRED":
|
|
173
|
-
import ssl
|
|
174
|
-
|
|
175
|
-
hypercorn_config["verify_mode"] = ssl.CERT_REQUIRED
|
|
176
|
-
elif verify_mode_str == "CERT_OPTIONAL":
|
|
177
|
-
import ssl
|
|
178
|
-
|
|
179
|
-
hypercorn_config["verify_mode"] = ssl.CERT_OPTIONAL
|
|
180
|
-
else:
|
|
181
|
-
hypercorn_config["verify_mode"] = verify_mode_str
|
|
182
|
-
|
|
183
|
-
# Add workers if specified
|
|
184
|
-
if "workers" in config and config["workers"]:
|
|
185
|
-
hypercorn_config["workers"] = config["workers"]
|
|
186
|
-
|
|
187
|
-
get_global_logger().info(f"Starting hypercorn server with config: {hypercorn_config}")
|
|
188
|
-
get_global_logger().info(f"SSL config from input: {config.get('ssl', 'NOT_FOUND')}")
|
|
189
|
-
get_global_logger().info(
|
|
190
|
-
f"Security SSL config: {config.get('security', {}).get('ssl', 'NOT_FOUND')}"
|
|
191
|
-
)
|
|
192
|
-
get_global_logger().info(
|
|
193
|
-
f"🔍 DEBUG: Hypercorn verify_mode: {hypercorn_config.get('verify_mode', 'NOT_SET')}"
|
|
194
|
-
)
|
|
195
|
-
get_global_logger().info(
|
|
196
|
-
f"🔍 DEBUG: Hypercorn ca_certs: {hypercorn_config.get('ca_certs', 'NOT_SET')}"
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
# Create config object
|
|
200
|
-
config_obj = hypercorn.Config()
|
|
201
|
-
for key, value in hypercorn_config.items():
|
|
202
|
-
setattr(config_obj, key, value)
|
|
203
|
-
|
|
204
|
-
# Run server
|
|
205
|
-
asyncio.run(hypercorn.asyncio.serve(app, config_obj))
|
|
206
|
-
|
|
207
|
-
except ImportError:
|
|
208
|
-
get_global_logger().error("hypercorn not installed. Install with: pip install hypercorn")
|
|
209
|
-
raise
|
|
210
|
-
except Exception as e:
|
|
211
|
-
get_global_logger().error(f"Failed to start hypercorn server: {e}")
|
|
212
|
-
raise
|
|
213
75
|
|
|
214
76
|
|
|
215
77
|
class ServerEngineFactory:
|
|
@@ -233,43 +95,10 @@ class ServerEngineFactory:
|
|
|
233
95
|
get_global_logger().info(f"Registered server engine: {engine.get_name()}")
|
|
234
96
|
|
|
235
97
|
@classmethod
|
|
236
|
-
def get_engine(cls, name: str) -> Optional[ServerEngine]:
|
|
237
|
-
"""
|
|
238
|
-
Get a server engine by name.
|
|
239
|
-
|
|
240
|
-
Args:
|
|
241
|
-
name: Name of the server engine
|
|
242
|
-
|
|
243
|
-
Returns:
|
|
244
|
-
Server engine instance or None if not found
|
|
245
|
-
"""
|
|
246
|
-
return cls._engines.get(name)
|
|
247
98
|
|
|
248
99
|
@classmethod
|
|
249
|
-
def get_available_engines(cls) -> Dict[str, ServerEngine]:
|
|
250
|
-
"""
|
|
251
|
-
Get all available server engines.
|
|
252
|
-
|
|
253
|
-
Returns:
|
|
254
|
-
Dictionary mapping engine names to engine instances
|
|
255
|
-
"""
|
|
256
|
-
return cls._engines.copy()
|
|
257
100
|
|
|
258
101
|
@classmethod
|
|
259
|
-
def get_engine_with_feature(cls, feature: str) -> Optional[ServerEngine]:
|
|
260
|
-
"""
|
|
261
|
-
Get the first available engine that supports a specific feature.
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
feature: Name of the feature to check
|
|
265
|
-
|
|
266
|
-
Returns:
|
|
267
|
-
Server engine that supports the feature or None
|
|
268
|
-
"""
|
|
269
|
-
for engine in cls._engines.values():
|
|
270
|
-
if engine.get_supported_features().get(feature, False):
|
|
271
|
-
return engine
|
|
272
|
-
return None
|
|
273
102
|
|
|
274
103
|
@classmethod
|
|
275
104
|
def initialize_default_engines(cls) -> None:
|
|
@@ -3,7 +3,6 @@ Settings management for the MCP Proxy Adapter framework.
|
|
|
3
3
|
Provides utilities for reading and managing framework settings from configuration.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from typing import Any, Dict, Optional, Union
|
|
7
6
|
from mcp_proxy_adapter.config import config
|
|
8
7
|
|
|
9
8
|
|
|
@@ -69,65 +68,10 @@ class Settings:
|
|
|
69
68
|
cls._custom_settings.clear()
|
|
70
69
|
|
|
71
70
|
@staticmethod
|
|
72
|
-
def get_server_settings() -> Dict[str, Any]:
|
|
73
|
-
"""
|
|
74
|
-
Get server configuration settings.
|
|
75
|
-
|
|
76
|
-
Returns:
|
|
77
|
-
Dictionary with server settings
|
|
78
|
-
"""
|
|
79
|
-
return {
|
|
80
|
-
"host": config.get("server.host", "0.0.0.0"),
|
|
81
|
-
"port": config.get("server.port", 8000),
|
|
82
|
-
"debug": config.get("server.debug", False),
|
|
83
|
-
"log_level": config.get("server.log_level", "INFO"),
|
|
84
|
-
}
|
|
85
71
|
|
|
86
72
|
@staticmethod
|
|
87
|
-
def get_logging_settings() -> Dict[str, Any]:
|
|
88
|
-
"""
|
|
89
|
-
Get logging configuration settings.
|
|
90
|
-
|
|
91
|
-
Returns:
|
|
92
|
-
Dictionary with logging settings
|
|
93
|
-
"""
|
|
94
|
-
return {
|
|
95
|
-
"level": config.get("logging.level", "INFO"),
|
|
96
|
-
"file": config.get("logging.file"),
|
|
97
|
-
"log_dir": config.get("logging.log_dir", "./logs"),
|
|
98
|
-
"log_file": config.get("logging.log_file", "mcp_proxy_adapter.log"),
|
|
99
|
-
"error_log_file": config.get(
|
|
100
|
-
"logging.error_log_file", "mcp_proxy_adapter_error.log"
|
|
101
|
-
),
|
|
102
|
-
"access_log_file": config.get(
|
|
103
|
-
"logging.access_log_file", "mcp_proxy_adapter_access.log"
|
|
104
|
-
),
|
|
105
|
-
"max_file_size": config.get("logging.max_file_size", "10MB"),
|
|
106
|
-
"backup_count": config.get("logging.backup_count", 5),
|
|
107
|
-
"format": config.get(
|
|
108
|
-
"logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
109
|
-
),
|
|
110
|
-
"date_format": config.get("logging.date_format", "%Y-%m-%d %H:%M:%S"),
|
|
111
|
-
"console_output": config.get("logging.console_output", True),
|
|
112
|
-
"file_output": config.get("logging.file_output", True),
|
|
113
|
-
}
|
|
114
73
|
|
|
115
74
|
@staticmethod
|
|
116
|
-
def get_commands_settings() -> Dict[str, Any]:
|
|
117
|
-
"""
|
|
118
|
-
Get commands configuration settings.
|
|
119
|
-
|
|
120
|
-
Returns:
|
|
121
|
-
Dictionary with commands settings
|
|
122
|
-
"""
|
|
123
|
-
return {
|
|
124
|
-
"auto_discovery": config.get("commands.auto_discovery", True),
|
|
125
|
-
"discovery_path": config.get(
|
|
126
|
-
"commands.discovery_path", "mcp_proxy_adapter.commands"
|
|
127
|
-
),
|
|
128
|
-
"auto_commands_path": config.get("commands.auto_commands_path"),
|
|
129
|
-
"custom_commands_path": config.get("commands.custom_commands_path"),
|
|
130
|
-
}
|
|
131
75
|
|
|
132
76
|
@staticmethod
|
|
133
77
|
def get_custom_setting(key: str, default: Any = None) -> Any:
|
|
@@ -144,16 +88,6 @@ class Settings:
|
|
|
144
88
|
return config.get(key, default)
|
|
145
89
|
|
|
146
90
|
@staticmethod
|
|
147
|
-
def get_all_settings() -> Dict[str, Any]:
|
|
148
|
-
"""
|
|
149
|
-
Get all configuration settings including custom settings.
|
|
150
|
-
|
|
151
|
-
Returns:
|
|
152
|
-
Dictionary with all configuration settings
|
|
153
|
-
"""
|
|
154
|
-
all_settings = config.get_all()
|
|
155
|
-
all_settings["custom_settings"] = Settings._custom_settings
|
|
156
|
-
return all_settings
|
|
157
91
|
|
|
158
92
|
@staticmethod
|
|
159
93
|
def set_custom_setting(key: str, value: Any) -> None:
|
|
@@ -194,11 +128,6 @@ class ServerSettings:
|
|
|
194
128
|
"""Get debug mode."""
|
|
195
129
|
return config.get("server.debug", False)
|
|
196
130
|
|
|
197
|
-
@staticmethod
|
|
198
|
-
def get_log_level() -> str:
|
|
199
|
-
"""Get log level."""
|
|
200
|
-
return config.get("server.log_level", "INFO")
|
|
201
|
-
|
|
202
131
|
|
|
203
132
|
class LoggingSettings:
|
|
204
133
|
"""
|
|
@@ -216,51 +145,22 @@ class LoggingSettings:
|
|
|
216
145
|
return config.get("logging.log_dir", "./logs")
|
|
217
146
|
|
|
218
147
|
@staticmethod
|
|
219
|
-
def get_log_file() -> Optional[str]:
|
|
220
|
-
"""Get main log file name."""
|
|
221
|
-
return config.get("logging.log_file", "mcp_proxy_adapter.log")
|
|
222
148
|
|
|
223
149
|
@staticmethod
|
|
224
|
-
def get_error_log_file() -> Optional[str]:
|
|
225
|
-
"""Get error log file name."""
|
|
226
|
-
return config.get("logging.error_log_file", "mcp_proxy_adapter_error.log")
|
|
227
150
|
|
|
228
151
|
@staticmethod
|
|
229
|
-
def get_access_log_file() -> Optional[str]:
|
|
230
|
-
"""Get access log file name."""
|
|
231
|
-
return config.get("logging.access_log_file", "mcp_proxy_adapter_access.log")
|
|
232
152
|
|
|
233
153
|
@staticmethod
|
|
234
|
-
def get_max_file_size() -> str:
|
|
235
|
-
"""Get max file size."""
|
|
236
|
-
return config.get("logging.max_file_size", "10MB")
|
|
237
154
|
|
|
238
155
|
@staticmethod
|
|
239
|
-
def get_backup_count() -> int:
|
|
240
|
-
"""Get backup count."""
|
|
241
|
-
return config.get("logging.backup_count", 5)
|
|
242
156
|
|
|
243
157
|
@staticmethod
|
|
244
|
-
def get_format() -> str:
|
|
245
|
-
"""Get log format."""
|
|
246
|
-
return config.get(
|
|
247
|
-
"logging.format", "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
248
|
-
)
|
|
249
158
|
|
|
250
159
|
@staticmethod
|
|
251
|
-
def get_date_format() -> str:
|
|
252
|
-
"""Get date format."""
|
|
253
|
-
return config.get("logging.date_format", "%Y-%m-%d %H:%M:%S")
|
|
254
160
|
|
|
255
161
|
@staticmethod
|
|
256
|
-
def get_console_output() -> bool:
|
|
257
|
-
"""Get console output setting."""
|
|
258
|
-
return config.get("logging.console_output", True)
|
|
259
162
|
|
|
260
163
|
@staticmethod
|
|
261
|
-
def get_file_output() -> bool:
|
|
262
|
-
"""Get file output setting."""
|
|
263
|
-
return config.get("logging.file_output", True)
|
|
264
164
|
|
|
265
165
|
|
|
266
166
|
class CommandsSettings:
|
|
@@ -279,35 +179,17 @@ class CommandsSettings:
|
|
|
279
179
|
return config.get("commands.discovery_path", "mcp_proxy_adapter.commands")
|
|
280
180
|
|
|
281
181
|
@staticmethod
|
|
282
|
-
def get_custom_commands_path() -> Optional[str]:
|
|
283
|
-
"""Get custom commands path."""
|
|
284
|
-
return config.get("commands.custom_commands_path")
|
|
285
182
|
|
|
286
183
|
|
|
287
184
|
# Convenience functions for easy access
|
|
288
|
-
def get_server_host() -> str:
|
|
289
|
-
"""Get server host."""
|
|
290
|
-
return ServerSettings.get_host()
|
|
291
185
|
|
|
292
186
|
|
|
293
|
-
def get_server_port() -> int:
|
|
294
|
-
"""Get server port."""
|
|
295
|
-
return ServerSettings.get_port()
|
|
296
187
|
|
|
297
188
|
|
|
298
|
-
def get_server_debug() -> bool:
|
|
299
|
-
"""Get server debug mode."""
|
|
300
|
-
return ServerSettings.get_debug()
|
|
301
189
|
|
|
302
190
|
|
|
303
|
-
def get_logging_level() -> str:
|
|
304
|
-
"""Get logging level."""
|
|
305
|
-
return LoggingSettings.get_level()
|
|
306
191
|
|
|
307
192
|
|
|
308
|
-
def get_logging_dir() -> str:
|
|
309
|
-
"""Get logging directory."""
|
|
310
|
-
return LoggingSettings.get_log_dir()
|
|
311
193
|
|
|
312
194
|
|
|
313
195
|
def get_auto_discovery() -> bool:
|
|
@@ -320,19 +202,10 @@ def get_discovery_path() -> str:
|
|
|
320
202
|
return CommandsSettings.get_discovery_path()
|
|
321
203
|
|
|
322
204
|
|
|
323
|
-
def get_setting(key: str, default: Any = None) -> Any:
|
|
324
|
-
"""Get any setting by key."""
|
|
325
|
-
return Settings.get_custom_setting(key, default)
|
|
326
205
|
|
|
327
206
|
|
|
328
|
-
def set_setting(key: str, value: Any) -> None:
|
|
329
|
-
"""Set any setting by key."""
|
|
330
|
-
Settings.set_custom_setting(key, value)
|
|
331
207
|
|
|
332
208
|
|
|
333
|
-
def reload_settings() -> None:
|
|
334
|
-
"""Reload all settings from configuration."""
|
|
335
|
-
Settings.reload_config()
|
|
336
209
|
|
|
337
210
|
|
|
338
211
|
def add_custom_settings(settings: Dict[str, Any]) -> None:
|
|
@@ -9,7 +9,6 @@ email: vasilyvz@gmail.com
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import signal
|
|
12
|
-
import asyncio
|
|
13
12
|
import threading
|
|
14
13
|
from typing import Optional, Callable, Any
|
|
15
14
|
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
@@ -56,42 +55,7 @@ class SignalHandler:
|
|
|
56
55
|
|
|
57
56
|
get_global_logger().info("Signal handlers installed for SIGTERM, SIGINT, SIGHUP")
|
|
58
57
|
|
|
59
|
-
def _handle_shutdown_signal(self, signum: int, frame: Any):
|
|
60
|
-
"""
|
|
61
|
-
Handle shutdown signals.
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
signum: Signal number
|
|
65
|
-
frame: Current stack frame
|
|
66
|
-
"""
|
|
67
|
-
signal_name = signal.Signals(signum).name
|
|
68
|
-
get_global_logger().info(f"🛑 Received {signal_name} signal, initiating graceful shutdown...")
|
|
69
|
-
|
|
70
|
-
# Set shutdown event
|
|
71
|
-
self._shutdown_event.set()
|
|
72
|
-
|
|
73
|
-
# Call shutdown callback if set
|
|
74
|
-
if self._shutdown_callback:
|
|
75
|
-
try:
|
|
76
|
-
get_global_logger().info("🔄 Executing shutdown callback...")
|
|
77
|
-
self._shutdown_callback()
|
|
78
|
-
get_global_logger().info("✅ Shutdown callback completed successfully")
|
|
79
|
-
except Exception as e:
|
|
80
|
-
get_global_logger().error(f"❌ Shutdown callback failed: {e}")
|
|
81
|
-
|
|
82
|
-
# Force exit immediately to avoid server hang
|
|
83
|
-
get_global_logger().info("🔄 Force exiting to avoid server hang...")
|
|
84
|
-
import os
|
|
85
|
-
# Use os._exit for immediate termination
|
|
86
|
-
get_global_logger().warning("⚠️ Using os._exit for immediate termination...")
|
|
87
|
-
os._exit(0)
|
|
88
58
|
|
|
89
|
-
def _force_exit(self):
|
|
90
|
-
"""Force exit if graceful shutdown takes too long."""
|
|
91
|
-
if self._shutdown_event.is_set():
|
|
92
|
-
get_global_logger().warning("⚠️ Forcing exit after timeout")
|
|
93
|
-
import os
|
|
94
|
-
os._exit(1)
|
|
95
59
|
|
|
96
60
|
def wait_for_shutdown(self, timeout: Optional[float] = None) -> bool:
|
|
97
61
|
"""
|
|
@@ -114,12 +78,6 @@ class SignalHandler:
|
|
|
114
78
|
"""
|
|
115
79
|
return self._shutdown_event.is_set()
|
|
116
80
|
|
|
117
|
-
def restore_handlers(self):
|
|
118
|
-
"""Restore original signal handlers."""
|
|
119
|
-
for sig, handler in self._original_handlers.items():
|
|
120
|
-
if handler is not None:
|
|
121
|
-
signal.signal(sig, handler)
|
|
122
|
-
get_global_logger().info("Original signal handlers restored")
|
|
123
81
|
|
|
124
82
|
|
|
125
83
|
# Global signal handler instance
|
|
@@ -134,31 +92,8 @@ def get_signal_handler() -> SignalHandler:
|
|
|
134
92
|
return _signal_handler
|
|
135
93
|
|
|
136
94
|
|
|
137
|
-
def setup_signal_handling(shutdown_callback: Optional[Callable] = None):
|
|
138
|
-
"""
|
|
139
|
-
Setup signal handling for graceful shutdown.
|
|
140
|
-
|
|
141
|
-
Args:
|
|
142
|
-
shutdown_callback: Optional callback to execute during shutdown
|
|
143
|
-
"""
|
|
144
|
-
handler = get_signal_handler()
|
|
145
|
-
if shutdown_callback:
|
|
146
|
-
handler.set_shutdown_callback(shutdown_callback)
|
|
147
|
-
get_global_logger().info("Signal handling setup completed")
|
|
148
95
|
|
|
149
96
|
|
|
150
|
-
def wait_for_shutdown_signal(timeout: Optional[float] = None) -> bool:
|
|
151
|
-
"""
|
|
152
|
-
Wait for shutdown signal.
|
|
153
|
-
|
|
154
|
-
Args:
|
|
155
|
-
timeout: Maximum time to wait in seconds
|
|
156
|
-
|
|
157
|
-
Returns:
|
|
158
|
-
True if shutdown signal received, False if timeout
|
|
159
|
-
"""
|
|
160
|
-
handler = get_signal_handler()
|
|
161
|
-
return handler.wait_for_shutdown(timeout)
|
|
162
97
|
|
|
163
98
|
|
|
164
99
|
def is_shutdown_requested() -> bool:
|
|
@@ -45,91 +45,6 @@ class SSLUtils:
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
@staticmethod
|
|
48
|
-
def create_ssl_context(
|
|
49
|
-
cert_file: str,
|
|
50
|
-
key_file: str,
|
|
51
|
-
ca_cert: Optional[str] = None,
|
|
52
|
-
verify_client: bool = False,
|
|
53
|
-
cipher_suites: Optional[List[str]] = None,
|
|
54
|
-
min_tls_version: str = "1.2",
|
|
55
|
-
max_tls_version: str = "1.3",
|
|
56
|
-
crl_config: Optional[Dict[str, Any]] = None,
|
|
57
|
-
) -> ssl.SSLContext:
|
|
58
|
-
"""
|
|
59
|
-
Create SSL context with specified configuration.
|
|
60
|
-
|
|
61
|
-
Args:
|
|
62
|
-
cert_file: Path to certificate file
|
|
63
|
-
key_file: Path to private key file
|
|
64
|
-
ca_cert: Path to CA certificate file (optional)
|
|
65
|
-
verify_client: Whether to verify client certificates
|
|
66
|
-
cipher_suites: List of cipher suites to use
|
|
67
|
-
min_tls_version: Minimum TLS version
|
|
68
|
-
max_tls_version: Maximum TLS version
|
|
69
|
-
crl_config: CRL configuration dictionary (optional)
|
|
70
|
-
|
|
71
|
-
Returns:
|
|
72
|
-
Configured SSL context
|
|
73
|
-
|
|
74
|
-
Raises:
|
|
75
|
-
ValueError: If certificate validation fails
|
|
76
|
-
FileNotFoundError: If certificate or key files not found
|
|
77
|
-
"""
|
|
78
|
-
# Validate certificate using AuthValidator
|
|
79
|
-
validator = AuthValidator()
|
|
80
|
-
result = validator.validate_certificate(cert_file)
|
|
81
|
-
if not result.is_valid:
|
|
82
|
-
raise ValueError(f"Invalid certificate: {result.error_message}")
|
|
83
|
-
|
|
84
|
-
# Check CRL if configured
|
|
85
|
-
if crl_config:
|
|
86
|
-
try:
|
|
87
|
-
crl_manager = CRLManager(crl_config)
|
|
88
|
-
if crl_manager.is_certificate_revoked(cert_file):
|
|
89
|
-
raise ValueError(
|
|
90
|
-
f"Certificate is revoked according to CRL: {cert_file}"
|
|
91
|
-
)
|
|
92
|
-
except Exception as e:
|
|
93
|
-
get_global_logger().error(f"CRL check failed: {e}")
|
|
94
|
-
# For security, fail if CRL check fails
|
|
95
|
-
raise ValueError(f"CRL validation failed: {e}")
|
|
96
|
-
|
|
97
|
-
# Check if files exist
|
|
98
|
-
if not Path(cert_file).exists():
|
|
99
|
-
raise FileNotFoundError(f"Certificate file not found: {cert_file}")
|
|
100
|
-
if not Path(key_file).exists():
|
|
101
|
-
raise FileNotFoundError(f"Key file not found: {key_file}")
|
|
102
|
-
if ca_cert and not Path(ca_cert).exists():
|
|
103
|
-
raise FileNotFoundError(f"CA certificate file not found: {ca_cert}")
|
|
104
|
-
|
|
105
|
-
# Create SSL context
|
|
106
|
-
if verify_client:
|
|
107
|
-
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
|
108
|
-
else:
|
|
109
|
-
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
|
|
110
|
-
|
|
111
|
-
# Load certificate and key
|
|
112
|
-
context.load_cert_chain(cert_file, key_file)
|
|
113
|
-
|
|
114
|
-
# Load CA certificate if provided
|
|
115
|
-
if ca_cert:
|
|
116
|
-
context.load_verify_locations(ca_cert)
|
|
117
|
-
|
|
118
|
-
# Configure client verification
|
|
119
|
-
if verify_client:
|
|
120
|
-
context.verify_mode = ssl.CERT_REQUIRED
|
|
121
|
-
context.check_hostname = False
|
|
122
|
-
else:
|
|
123
|
-
context.verify_mode = ssl.CERT_NONE
|
|
124
|
-
|
|
125
|
-
# Setup cipher suites
|
|
126
|
-
SSLUtils.setup_cipher_suites(context, cipher_suites or [])
|
|
127
|
-
|
|
128
|
-
# Setup TLS versions
|
|
129
|
-
SSLUtils.setup_tls_versions(context, min_tls_version, max_tls_version)
|
|
130
|
-
|
|
131
|
-
get_global_logger().info(f"SSL context created successfully with cert: {cert_file}")
|
|
132
|
-
return context
|
|
133
48
|
|
|
134
49
|
@staticmethod
|
|
135
50
|
def validate_certificate(
|
|
@@ -225,55 +140,22 @@ class SSLUtils:
|
|
|
225
140
|
get_global_logger().error(f"Failed to set TLS versions: {e}")
|
|
226
141
|
|
|
227
142
|
@staticmethod
|
|
228
|
-
def
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
return
|
|
247
|
-
|
|
248
|
-
@staticmethod
|
|
249
|
-
def get_ssl_config_for_hypercorn(ssl_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
250
|
-
"""
|
|
251
|
-
Get SSL configuration for hypercorn from transport configuration.
|
|
252
|
-
|
|
253
|
-
Args:
|
|
254
|
-
ssl_config: SSL configuration from transport manager
|
|
255
|
-
|
|
256
|
-
Returns:
|
|
257
|
-
Configuration for hypercorn
|
|
258
|
-
"""
|
|
259
|
-
hypercorn_ssl = {}
|
|
260
|
-
|
|
261
|
-
if not ssl_config:
|
|
262
|
-
return hypercorn_ssl
|
|
263
|
-
|
|
264
|
-
# Basic SSL parameters
|
|
265
|
-
if ssl_config.get("cert_file"):
|
|
266
|
-
hypercorn_ssl["certfile"] = ssl_config["cert_file"]
|
|
267
|
-
|
|
268
|
-
if ssl_config.get("key_file"):
|
|
269
|
-
hypercorn_ssl["keyfile"] = ssl_config["key_file"]
|
|
270
|
-
|
|
271
|
-
if ssl_config.get("ca_cert"):
|
|
272
|
-
hypercorn_ssl["ca_certs"] = ssl_config["ca_cert"]
|
|
273
|
-
|
|
274
|
-
# Client verification mode
|
|
275
|
-
if ssl_config.get("verify_client", False):
|
|
276
|
-
hypercorn_ssl["verify_mode"] = "CERT_REQUIRED"
|
|
277
|
-
|
|
278
|
-
get_global_logger().info(f"Generated hypercorn SSL config: {hypercorn_ssl}")
|
|
279
|
-
return hypercorn_ssl
|
|
143
|
+
def create_ssl_context(
|
|
144
|
+
cert_file: Optional[str] = None,
|
|
145
|
+
key_file: Optional[str] = None,
|
|
146
|
+
ca_file: Optional[str] = None,
|
|
147
|
+
verify_mode: int = ssl.CERT_REQUIRED,
|
|
148
|
+
check_hostname: bool = True,
|
|
149
|
+
) -> ssl.SSLContext:
|
|
150
|
+
"""Create SSL context with proper configuration."""
|
|
151
|
+
context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
|
|
152
|
+
context.check_hostname = check_hostname
|
|
153
|
+
context.verify_mode = verify_mode
|
|
154
|
+
|
|
155
|
+
if cert_file and key_file:
|
|
156
|
+
context.load_cert_chain(cert_file, key_file)
|
|
157
|
+
|
|
158
|
+
if ca_file:
|
|
159
|
+
context.load_verify_locations(ca_file)
|
|
160
|
+
|
|
161
|
+
return context
|