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
mcp_proxy_adapter/core/client.py
CHANGED
|
@@ -14,13 +14,12 @@ import json
|
|
|
14
14
|
import os
|
|
15
15
|
import ssl
|
|
16
16
|
import time
|
|
17
|
-
from typing import Dict, Any, Optional, List, Union
|
|
18
|
-
from urllib.parse import urljoin
|
|
19
17
|
from pathlib import Path
|
|
18
|
+
from typing import Any, Dict, Optional
|
|
19
|
+
from urllib.parse import urljoin
|
|
20
20
|
|
|
21
21
|
import aiohttp
|
|
22
22
|
import requests
|
|
23
|
-
from requests.exceptions import RequestException
|
|
24
23
|
|
|
25
24
|
# Import security framework components
|
|
26
25
|
try:
|
|
@@ -29,17 +28,11 @@ try:
|
|
|
29
28
|
AuthManager,
|
|
30
29
|
CertificateManager,
|
|
31
30
|
PermissionManager,
|
|
32
|
-
)
|
|
33
|
-
from mcp_security_framework.utils import (
|
|
34
31
|
generate_api_key,
|
|
35
32
|
create_jwt_token,
|
|
36
33
|
validate_jwt_token,
|
|
37
|
-
)
|
|
38
|
-
from mcp_security_framework.utils import (
|
|
39
34
|
extract_roles_from_cert,
|
|
40
35
|
validate_certificate_chain,
|
|
41
|
-
)
|
|
42
|
-
from mcp_security_framework.utils import (
|
|
43
36
|
create_ssl_context,
|
|
44
37
|
validate_server_certificate,
|
|
45
38
|
)
|
|
@@ -47,6 +40,14 @@ try:
|
|
|
47
40
|
SECURITY_FRAMEWORK_AVAILABLE = True
|
|
48
41
|
except ImportError:
|
|
49
42
|
SECURITY_FRAMEWORK_AVAILABLE = False
|
|
43
|
+
# Define stubs for missing imports
|
|
44
|
+
generate_api_key = None
|
|
45
|
+
create_jwt_token = None
|
|
46
|
+
validate_jwt_token = None
|
|
47
|
+
extract_roles_from_cert = None
|
|
48
|
+
validate_certificate_chain = None
|
|
49
|
+
create_ssl_context = None
|
|
50
|
+
validate_server_certificate = None
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
class UniversalClient:
|
|
@@ -213,14 +213,6 @@ class ClientManager:
|
|
|
213
213
|
self.get_global_logger().error(f"Failed to get status for client {client_id}: {e}")
|
|
214
214
|
return {"error": str(e)}
|
|
215
215
|
|
|
216
|
-
async def list_clients(self) -> List[str]:
|
|
217
|
-
"""
|
|
218
|
-
Get list of all client identifiers.
|
|
219
|
-
|
|
220
|
-
Returns:
|
|
221
|
-
List of client identifiers
|
|
222
|
-
"""
|
|
223
|
-
return list(self.clients.keys())
|
|
224
216
|
|
|
225
217
|
async def cleanup(self):
|
|
226
218
|
"""Clean up all client connections."""
|
|
@@ -237,17 +229,6 @@ class ClientManager:
|
|
|
237
229
|
await self.cleanup()
|
|
238
230
|
|
|
239
231
|
|
|
240
|
-
def create_client_manager(config: Dict[str, Any]) -> ClientManager:
|
|
241
|
-
"""
|
|
242
|
-
Create a ClientManager instance.
|
|
243
|
-
|
|
244
|
-
Args:
|
|
245
|
-
config: Client manager configuration
|
|
246
|
-
|
|
247
|
-
Returns:
|
|
248
|
-
ClientManager instance
|
|
249
|
-
"""
|
|
250
|
-
return ClientManager(config)
|
|
251
232
|
|
|
252
233
|
|
|
253
234
|
# Example usage and testing functions
|
|
@@ -15,7 +15,6 @@ from pathlib import Path
|
|
|
15
15
|
|
|
16
16
|
# Import framework utilities
|
|
17
17
|
try:
|
|
18
|
-
from mcp_security_framework.utils.crypto_utils import (
|
|
19
18
|
generate_api_key,
|
|
20
19
|
create_jwt_token,
|
|
21
20
|
verify_jwt_token,
|
|
@@ -27,7 +26,6 @@ try:
|
|
|
27
26
|
validate_certificate_format,
|
|
28
27
|
)
|
|
29
28
|
from mcp_security_framework.core.ssl_manager import SSLManager
|
|
30
|
-
from mcp_security_framework.schemas.config import SSLConfig, AuthConfig
|
|
31
29
|
from mcp_security_framework.schemas.models import AuthResult, ValidationResult
|
|
32
30
|
|
|
33
31
|
SECURITY_FRAMEWORK_AVAILABLE = True
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Configuration management package for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .config import Config
|
|
9
|
+
from .config_loader import ConfigLoader
|
|
10
|
+
from .feature_manager import FeatureManager
|
|
11
|
+
from .config_factory import ConfigFactory
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"Config",
|
|
15
|
+
"ConfigLoader",
|
|
16
|
+
"FeatureManager",
|
|
17
|
+
"ConfigFactory",
|
|
18
|
+
]
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Main configuration class for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, Optional, List
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
12
|
+
from .config_loader import ConfigLoader
|
|
13
|
+
from .feature_manager import FeatureManager
|
|
14
|
+
from .config_factory import ConfigFactory
|
|
15
|
+
|
|
16
|
+
# Import validation if available
|
|
17
|
+
try:
|
|
18
|
+
VALIDATION_AVAILABLE = True
|
|
19
|
+
except ImportError:
|
|
20
|
+
VALIDATION_AVAILABLE = False
|
|
21
|
+
|
|
22
|
+
# Import configuration errors
|
|
23
|
+
from ..errors import ConfigError, ValidationResult
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Config:
|
|
27
|
+
"""
|
|
28
|
+
Configuration management class for the microservice.
|
|
29
|
+
Allows loading settings from configuration file and environment variables.
|
|
30
|
+
Supports optional features that can be enabled/disabled.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self, config_path: Optional[str] = None, validate_on_load: bool = False):
|
|
34
|
+
"""
|
|
35
|
+
Initialize configuration.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
config_path: Path to configuration file. If not specified,
|
|
39
|
+
"./config.json" is used.
|
|
40
|
+
validate_on_load: Whether to validate configuration on load (default: False)
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
ConfigError: If configuration validation fails
|
|
44
|
+
"""
|
|
45
|
+
self.config_path = config_path or "./config.json"
|
|
46
|
+
self.config_data: Dict[str, Any] = {}
|
|
47
|
+
self.validate_on_load = validate_on_load
|
|
48
|
+
self.validation_results: List[ValidationResult] = []
|
|
49
|
+
self.validator = None
|
|
50
|
+
|
|
51
|
+
# Initialize components
|
|
52
|
+
self.logger = get_global_logger()
|
|
53
|
+
self.loader = ConfigLoader()
|
|
54
|
+
self.feature_manager = FeatureManager(self.config_data)
|
|
55
|
+
self.factory = ConfigFactory()
|
|
56
|
+
|
|
57
|
+
# Load configuration
|
|
58
|
+
self.load_config()
|
|
59
|
+
|
|
60
|
+
def load_config(self) -> None:
|
|
61
|
+
"""Load configuration from file and environment variables."""
|
|
62
|
+
try:
|
|
63
|
+
# Load from file if it exists
|
|
64
|
+
if Path(self.config_path).exists():
|
|
65
|
+
file_config = self.loader.load_from_file(self.config_path)
|
|
66
|
+
self.config_data.update(file_config)
|
|
67
|
+
|
|
68
|
+
# Load from environment variables
|
|
69
|
+
try:
|
|
70
|
+
env_config = self.loader.load_from_env()
|
|
71
|
+
self._merge_config(env_config)
|
|
72
|
+
except AttributeError:
|
|
73
|
+
# load_from_env doesn't exist yet, skip
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
# Validate if required
|
|
77
|
+
if self.validate_on_load and VALIDATION_AVAILABLE:
|
|
78
|
+
self.validate()
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
self.logger.error(f"Failed to load configuration: {e}")
|
|
82
|
+
raise ConfigError(f"Configuration loading failed: {e}")
|
|
83
|
+
|
|
84
|
+
def _merge_config(self, new_config: Dict[str, Any]) -> None:
|
|
85
|
+
"""
|
|
86
|
+
Merge new configuration into existing configuration.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
new_config: New configuration to merge
|
|
90
|
+
"""
|
|
91
|
+
for section, values in new_config.items():
|
|
92
|
+
if section in self.config_data:
|
|
93
|
+
if isinstance(self.config_data[section], dict) and isinstance(values, dict):
|
|
94
|
+
self.config_data[section].update(values)
|
|
95
|
+
else:
|
|
96
|
+
self.config_data[section] = values
|
|
97
|
+
else:
|
|
98
|
+
self.config_data[section] = values
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def enable_feature(self, feature: str) -> None:
|
|
105
|
+
"""
|
|
106
|
+
Enable a feature.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
feature: Feature name
|
|
110
|
+
"""
|
|
111
|
+
self.feature_manager.enable_feature(feature)
|
|
112
|
+
|
|
113
|
+
def disable_feature(self, feature: str) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Disable a feature.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
feature: Feature name
|
|
119
|
+
"""
|
|
120
|
+
self.feature_manager.disable_feature(feature)
|
|
121
|
+
|
|
122
|
+
def is_feature_enabled(self, feature: str) -> bool:
|
|
123
|
+
"""
|
|
124
|
+
Check if feature is enabled.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
feature: Feature name
|
|
128
|
+
|
|
129
|
+
Returns:
|
|
130
|
+
True if enabled, False otherwise
|
|
131
|
+
"""
|
|
132
|
+
return self.feature_manager.is_feature_enabled(feature)
|
|
133
|
+
|
|
134
|
+
def get_enabled_features(self) -> List[str]:
|
|
135
|
+
"""
|
|
136
|
+
Get list of enabled features.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
List of enabled feature names
|
|
140
|
+
"""
|
|
141
|
+
return self.feature_manager.get_enabled_features()
|
|
142
|
+
|
|
143
|
+
def validate(self) -> List[ValidationResult]:
|
|
144
|
+
"""
|
|
145
|
+
Validate configuration.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
List of validation results
|
|
149
|
+
"""
|
|
150
|
+
if not VALIDATION_AVAILABLE:
|
|
151
|
+
self.logger.warning("Configuration validation not available")
|
|
152
|
+
return []
|
|
153
|
+
|
|
154
|
+
try:
|
|
155
|
+
self.validator = ConfigValidator()
|
|
156
|
+
self.validator.config_data = self.config_data
|
|
157
|
+
self.validation_results = self.validator.validate_config()
|
|
158
|
+
return self.validation_results
|
|
159
|
+
except Exception as e:
|
|
160
|
+
self.logger.error(f"Configuration validation failed: {e}")
|
|
161
|
+
return []
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def get_validation_errors(self) -> List[ValidationResult]:
|
|
165
|
+
"""Get validation errors."""
|
|
166
|
+
return [result for result in self.validation_results if result.level == "error"]
|
|
167
|
+
|
|
168
|
+
def get_validation_warnings(self) -> List[ValidationResult]:
|
|
169
|
+
"""Get validation warnings."""
|
|
170
|
+
return [result for result in self.validation_results if result.level == "warning"]
|
|
171
|
+
|
|
172
|
+
def get_validation_summary(self) -> Dict[str, Any]:
|
|
173
|
+
"""Get validation summary."""
|
|
174
|
+
errors = self.get_validation_errors()
|
|
175
|
+
warnings = self.get_validation_warnings()
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
"total": len(self.validation_results),
|
|
179
|
+
"errors": len(errors),
|
|
180
|
+
"warnings": len(warnings),
|
|
181
|
+
"is_valid": len(errors) == 0
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def check_feature_requirements(self, feature: str) -> List[ValidationResult]:
|
|
186
|
+
"""
|
|
187
|
+
Check feature requirements.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
feature: Feature name
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
List of validation results
|
|
194
|
+
"""
|
|
195
|
+
return self.feature_manager.check_feature_requirements(feature)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Configuration factory for creating predefined configurations.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Dict, Any
|
|
9
|
+
|
|
10
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ConfigFactory:
|
|
14
|
+
"""Factory for creating predefined configurations."""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
"""Initialize config factory."""
|
|
18
|
+
self.logger = get_global_logger()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Configuration loading utilities for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConfigLoader:
|
|
17
|
+
"""Loader for configuration files and environment variables."""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
"""Initialize config loader."""
|
|
21
|
+
self.logger = get_global_logger()
|
|
22
|
+
|
|
23
|
+
def load_from_file(self, config_path: str | Path) -> dict:
|
|
24
|
+
"""
|
|
25
|
+
Load configuration from JSON file.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
config_path: Path to configuration file
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Configuration dictionary
|
|
32
|
+
|
|
33
|
+
Raises:
|
|
34
|
+
FileNotFoundError: If config file doesn't exist
|
|
35
|
+
json.JSONDecodeError: If config file is invalid JSON
|
|
36
|
+
"""
|
|
37
|
+
path = Path(config_path)
|
|
38
|
+
if not path.exists():
|
|
39
|
+
raise FileNotFoundError(f"Configuration file not found: {config_path}")
|
|
40
|
+
|
|
41
|
+
with open(path, 'r', encoding='utf-8') as f:
|
|
42
|
+
return json.load(f)
|
|
43
|
+
|
|
44
|
+
def _convert_env_value(self, value: str) -> Any:
|
|
45
|
+
"""
|
|
46
|
+
Convert environment variable value to appropriate type.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
value: Value as string
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Converted value
|
|
53
|
+
"""
|
|
54
|
+
# Try to convert to appropriate type
|
|
55
|
+
if value.lower() == "true":
|
|
56
|
+
return True
|
|
57
|
+
elif value.lower() == "false":
|
|
58
|
+
return False
|
|
59
|
+
elif value.isdigit():
|
|
60
|
+
return int(value)
|
|
61
|
+
else:
|
|
62
|
+
try:
|
|
63
|
+
return float(value)
|
|
64
|
+
except ValueError:
|
|
65
|
+
return value
|
|
66
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Feature management utilities for MCP Proxy Adapter configuration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, List
|
|
9
|
+
|
|
10
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FeatureManager:
|
|
14
|
+
"""Manager for configuration features."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, config_data: Dict[str, Any]):
|
|
17
|
+
"""
|
|
18
|
+
Initialize feature manager.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
config_data: Configuration data dictionary
|
|
22
|
+
"""
|
|
23
|
+
self.config_data = config_data
|
|
24
|
+
self.logger = get_global_logger()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Simple configuration data container and IO helpers for MCP Proxy Adapter.
|
|
6
|
+
|
|
7
|
+
This module provides a minimal, explicit configuration model with three
|
|
8
|
+
sections: server, proxy_client and auth.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any, Dict, List, Optional
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ServerConfig:
|
|
21
|
+
host: str
|
|
22
|
+
port: int
|
|
23
|
+
protocol: str # http | https | mtls
|
|
24
|
+
cert_file: Optional[str] = None
|
|
25
|
+
key_file: Optional[str] = None
|
|
26
|
+
ca_cert_file: Optional[str] = None
|
|
27
|
+
crl_file: Optional[str] = None
|
|
28
|
+
log_dir: str = "./logs"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class HeartbeatConfig:
|
|
33
|
+
endpoint: str = "/heartbeat"
|
|
34
|
+
interval: int = 30
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass
|
|
38
|
+
class RegistrationConfig:
|
|
39
|
+
register_endpoint: str = "/register"
|
|
40
|
+
unregister_endpoint: str = "/unregister"
|
|
41
|
+
auto_on_startup: bool = True
|
|
42
|
+
auto_on_shutdown: bool = True
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class ProxyClientConfig:
|
|
47
|
+
enabled: bool = False
|
|
48
|
+
host: str = "localhost"
|
|
49
|
+
port: int = 3005
|
|
50
|
+
protocol: str = "http"
|
|
51
|
+
cert_file: Optional[str] = None
|
|
52
|
+
key_file: Optional[str] = None
|
|
53
|
+
ca_cert_file: Optional[str] = None
|
|
54
|
+
crl_file: Optional[str] = None
|
|
55
|
+
heartbeat: HeartbeatConfig = field(default_factory=HeartbeatConfig)
|
|
56
|
+
registration: RegistrationConfig = field(default_factory=RegistrationConfig)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class AuthConfig:
|
|
61
|
+
use_token: bool = False
|
|
62
|
+
use_roles: bool = False
|
|
63
|
+
tokens: Dict[str, List[str]] = field(default_factory=dict)
|
|
64
|
+
roles: Dict[str, List[str]] = field(default_factory=dict)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class SimpleConfigModel:
|
|
69
|
+
server: ServerConfig
|
|
70
|
+
proxy_client: ProxyClientConfig = field(default_factory=ProxyClientConfig)
|
|
71
|
+
auth: AuthConfig = field(default_factory=AuthConfig)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class SimpleConfig:
|
|
75
|
+
"""High-level loader/saver for SimpleConfigModel."""
|
|
76
|
+
|
|
77
|
+
def __init__(self, config_path: str = "config.json") -> None:
|
|
78
|
+
self.config_path: Path = Path(config_path)
|
|
79
|
+
self.model: Optional[SimpleConfigModel] = None
|
|
80
|
+
|
|
81
|
+
def load(self) -> SimpleConfigModel:
|
|
82
|
+
content = json.loads(self.config_path.read_text(encoding="utf-8"))
|
|
83
|
+
server = ServerConfig(**content["server"]) # type: ignore[arg-type]
|
|
84
|
+
proxy_client = ProxyClientConfig(**content.get("proxy_client", {})) # type: ignore[arg-type]
|
|
85
|
+
# Nested structures for proxy client (heartbeat/registration)
|
|
86
|
+
if isinstance(content.get("proxy_client"), dict):
|
|
87
|
+
pc = content["proxy_client"]
|
|
88
|
+
if isinstance(pc.get("heartbeat"), dict):
|
|
89
|
+
proxy_client.heartbeat = HeartbeatConfig(**pc["heartbeat"]) # type: ignore[arg-type]
|
|
90
|
+
if isinstance(pc.get("registration"), dict):
|
|
91
|
+
proxy_client.registration = RegistrationConfig(**pc["registration"]) # type: ignore[arg-type]
|
|
92
|
+
auth = AuthConfig(**content.get("auth", {})) # type: ignore[arg-type]
|
|
93
|
+
self.model = SimpleConfigModel(server=server, proxy_client=proxy_client, auth=auth)
|
|
94
|
+
return self.model
|
|
95
|
+
|
|
96
|
+
def save(self, out_path: Optional[str] = None) -> None:
|
|
97
|
+
if self.model is None:
|
|
98
|
+
raise ValueError("Configuration model is not loaded")
|
|
99
|
+
path = Path(out_path) if out_path else self.config_path
|
|
100
|
+
data: Dict[str, Any] = {
|
|
101
|
+
"server": vars(self.model.server),
|
|
102
|
+
"proxy_client": {
|
|
103
|
+
**{k: v for k, v in vars(self.model.proxy_client).items() if k not in {"heartbeat", "registration"}},
|
|
104
|
+
"heartbeat": vars(self.model.proxy_client.heartbeat),
|
|
105
|
+
"registration": vars(self.model.proxy_client.registration),
|
|
106
|
+
},
|
|
107
|
+
"auth": vars(self.model.auth),
|
|
108
|
+
}
|
|
109
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
110
|
+
path.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
111
|
+
|
|
112
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Simple configuration generator for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
from .simple_config import (
|
|
13
|
+
SimpleConfig,
|
|
14
|
+
SimpleConfigModel,
|
|
15
|
+
ServerConfig,
|
|
16
|
+
ProxyClientConfig,
|
|
17
|
+
AuthConfig,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SimpleConfigGenerator:
|
|
22
|
+
"""Generate minimal configuration according to the plan."""
|
|
23
|
+
|
|
24
|
+
def generate(self, protocol: str, with_proxy: bool = False, out_path: str = "config.json") -> str:
|
|
25
|
+
server = ServerConfig(host="0.0.0.0", port=8080, protocol=protocol)
|
|
26
|
+
if protocol in ("https", "mtls"):
|
|
27
|
+
server.cert_file = "./certs/server.crt"
|
|
28
|
+
server.key_file = "./certs/server.key"
|
|
29
|
+
if protocol == "mtls":
|
|
30
|
+
server.ca_cert_file = "./certs/ca.crt"
|
|
31
|
+
|
|
32
|
+
proxy = ProxyClientConfig(enabled=with_proxy)
|
|
33
|
+
if with_proxy:
|
|
34
|
+
proxy.protocol = protocol
|
|
35
|
+
proxy.host = "localhost"
|
|
36
|
+
proxy.port = 3005
|
|
37
|
+
if protocol in ("https", "mtls"):
|
|
38
|
+
proxy.cert_file = "./certs/client.crt"
|
|
39
|
+
proxy.key_file = "./certs/client.key"
|
|
40
|
+
if protocol == "mtls":
|
|
41
|
+
proxy.ca_cert_file = "./certs/ca.crt"
|
|
42
|
+
|
|
43
|
+
auth = AuthConfig(use_token=False, use_roles=False, tokens={}, roles={})
|
|
44
|
+
|
|
45
|
+
cfg = SimpleConfig()
|
|
46
|
+
cfg.model = SimpleConfigModel(server=server, proxy_client=proxy, auth=auth)
|
|
47
|
+
cfg.save(out_path)
|
|
48
|
+
return out_path
|
|
49
|
+
|
|
50
|
+
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Simple configuration validator ensuring required fields and files exist.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from dataclasses import dataclass
|
|
12
|
+
from typing import List
|
|
13
|
+
|
|
14
|
+
from .simple_config import SimpleConfigModel
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class ValidationError:
|
|
19
|
+
message: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SimpleConfigValidator:
|
|
23
|
+
"""Validate SimpleConfigModel instances."""
|
|
24
|
+
|
|
25
|
+
def validate(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
26
|
+
errors: List[ValidationError] = []
|
|
27
|
+
errors.extend(self._validate_server(model))
|
|
28
|
+
errors.extend(self._validate_proxy_client(model))
|
|
29
|
+
errors.extend(self._validate_auth(model))
|
|
30
|
+
return errors
|
|
31
|
+
|
|
32
|
+
def _validate_server(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
33
|
+
e: List[ValidationError] = []
|
|
34
|
+
s = model.server
|
|
35
|
+
if not s.host:
|
|
36
|
+
e.append(ValidationError("server.host is required"))
|
|
37
|
+
if not isinstance(s.port, int):
|
|
38
|
+
e.append(ValidationError("server.port must be integer"))
|
|
39
|
+
if s.protocol not in ("http", "https", "mtls"):
|
|
40
|
+
e.append(ValidationError("server.protocol must be one of: http, https, mtls"))
|
|
41
|
+
if s.protocol in ("https", "mtls"):
|
|
42
|
+
if not s.cert_file:
|
|
43
|
+
e.append(ValidationError(f"server.cert_file is required for {s.protocol}"))
|
|
44
|
+
if not s.key_file:
|
|
45
|
+
e.append(ValidationError(f"server.key_file is required for {s.protocol}"))
|
|
46
|
+
if s.protocol == "mtls" and not s.ca_cert_file:
|
|
47
|
+
e.append(ValidationError("server.ca_cert_file is required for mtls"))
|
|
48
|
+
# Files existence (if provided)
|
|
49
|
+
for label, path in ("cert_file", s.cert_file), ("key_file", s.key_file), ("ca_cert_file", s.ca_cert_file), ("crl_file", s.crl_file):
|
|
50
|
+
if path and not os.path.exists(path):
|
|
51
|
+
e.append(ValidationError(f"server.{label} not found: {path}"))
|
|
52
|
+
return e
|
|
53
|
+
|
|
54
|
+
def _validate_proxy_client(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
55
|
+
e: List[ValidationError] = []
|
|
56
|
+
pc = model.proxy_client
|
|
57
|
+
if pc.enabled:
|
|
58
|
+
if not pc.host:
|
|
59
|
+
e.append(ValidationError("proxy_client.host is required when enabled"))
|
|
60
|
+
if not isinstance(pc.port, int):
|
|
61
|
+
e.append(ValidationError("proxy_client.port must be integer"))
|
|
62
|
+
if pc.protocol not in ("http", "https", "mtls"):
|
|
63
|
+
e.append(ValidationError("proxy_client.protocol must be one of: http, https, mtls"))
|
|
64
|
+
if pc.protocol in ("https", "mtls"):
|
|
65
|
+
if not pc.cert_file:
|
|
66
|
+
e.append(ValidationError(f"proxy_client.cert_file is required for {pc.protocol}"))
|
|
67
|
+
if not pc.key_file:
|
|
68
|
+
e.append(ValidationError(f"proxy_client.key_file is required for {pc.protocol}"))
|
|
69
|
+
if pc.protocol == "mtls" and not pc.ca_cert_file:
|
|
70
|
+
e.append(ValidationError("proxy_client.ca_cert_file is required for mtls"))
|
|
71
|
+
# Files existence (if provided)
|
|
72
|
+
for label, path in ("cert_file", pc.cert_file), ("key_file", pc.key_file), ("ca_cert_file", pc.ca_cert_file), ("crl_file", pc.crl_file):
|
|
73
|
+
if path and not os.path.exists(path):
|
|
74
|
+
e.append(ValidationError(f"proxy_client.{label} not found: {path}"))
|
|
75
|
+
# Heartbeat
|
|
76
|
+
if not pc.heartbeat.endpoint:
|
|
77
|
+
e.append(ValidationError("proxy_client.heartbeat.endpoint is required"))
|
|
78
|
+
if not isinstance(pc.heartbeat.interval, int) or pc.heartbeat.interval <= 0:
|
|
79
|
+
e.append(ValidationError("proxy_client.heartbeat.interval must be positive integer"))
|
|
80
|
+
# Registration endpoints
|
|
81
|
+
if not pc.registration.register_endpoint:
|
|
82
|
+
e.append(ValidationError("proxy_client.registration.register_endpoint is required"))
|
|
83
|
+
if not pc.registration.unregister_endpoint:
|
|
84
|
+
e.append(ValidationError("proxy_client.registration.unregister_endpoint is required"))
|
|
85
|
+
return e
|
|
86
|
+
|
|
87
|
+
def _validate_auth(self, model: SimpleConfigModel) -> List[ValidationError]:
|
|
88
|
+
e: List[ValidationError] = []
|
|
89
|
+
a = model.auth
|
|
90
|
+
if a.use_roles and not a.use_token:
|
|
91
|
+
e.append(ValidationError("auth.use_roles requires auth.use_token to be true"))
|
|
92
|
+
if a.use_token and not a.tokens:
|
|
93
|
+
e.append(ValidationError("auth.tokens must be provided when auth.use_token is true"))
|
|
94
|
+
return e
|
|
95
|
+
|
|
96
|
+
|