mcp-proxy-adapter 6.9.27__py3-none-any.whl → 6.9.29__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 +0 -6
- 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 -912
- 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.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.9.29.dist-info/RECORD +235 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/entry_points.txt +1 -1
- mcp_proxy_adapter-6.9.27.dist-info/RECORD +0 -149
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/top_level.txt +0 -0
mcp_proxy_adapter/api/tools.py
CHANGED
|
@@ -72,14 +72,6 @@ class TSTCommandExecutor:
|
|
|
72
72
|
raise
|
|
73
73
|
|
|
74
74
|
@classmethod
|
|
75
|
-
def get_schema(cls) -> Dict[str, Any]:
|
|
76
|
-
"""
|
|
77
|
-
Возвращает схему инструмента в формате OpenAPI.
|
|
78
|
-
|
|
79
|
-
Returns:
|
|
80
|
-
Словарь со схемой инструмента
|
|
81
|
-
"""
|
|
82
|
-
return ToolIntegration.generate_tool_schema(cls.name, registry, cls.description)
|
|
83
75
|
|
|
84
76
|
@classmethod
|
|
85
77
|
def get_description(cls, format: str = "json") -> Union[Dict[str, Any], str]:
|
|
@@ -167,43 +159,5 @@ class TSTCommandExecutor:
|
|
|
167
159
|
available_tools = {TSTCommandExecutor.name: TSTCommandExecutor}
|
|
168
160
|
|
|
169
161
|
|
|
170
|
-
def get_tool_description(
|
|
171
|
-
tool_name: str, format: str = "json"
|
|
172
|
-
) -> Union[Dict[str, Any], str]:
|
|
173
|
-
"""
|
|
174
|
-
Получает описание инструмента API по имени.
|
|
175
|
-
|
|
176
|
-
Args:
|
|
177
|
-
tool_name: Имя инструмента API
|
|
178
|
-
format: Формат описания (json, markdown, html)
|
|
179
|
-
|
|
180
|
-
Returns:
|
|
181
|
-
Описание инструмента в указанном формате
|
|
182
162
|
|
|
183
|
-
Raises:
|
|
184
|
-
NotFoundError: Если инструмент не найден
|
|
185
|
-
"""
|
|
186
|
-
if tool_name in available_tools:
|
|
187
|
-
return available_tools[tool_name].get_description(format)
|
|
188
|
-
else:
|
|
189
|
-
raise NotFoundError(f"Инструмент '{tool_name}' не найден")
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
async def execute_tool(tool_name: str, **params) -> Dict[str, Any]:
|
|
193
|
-
"""
|
|
194
|
-
Выполняет инструмент API с указанными параметрами.
|
|
195
163
|
|
|
196
|
-
Args:
|
|
197
|
-
tool_name: Имя инструмента API
|
|
198
|
-
**params: Параметры инструмента
|
|
199
|
-
|
|
200
|
-
Returns:
|
|
201
|
-
Результат выполнения инструмента
|
|
202
|
-
|
|
203
|
-
Raises:
|
|
204
|
-
NotFoundError: Если инструмент не найден
|
|
205
|
-
"""
|
|
206
|
-
if tool_name in available_tools:
|
|
207
|
-
return await available_tools[tool_name].execute(**params)
|
|
208
|
-
else:
|
|
209
|
-
raise NotFoundError(f"Инструмент '{tool_name}' не найден")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI Commands Module
|
|
3
|
+
|
|
4
|
+
This module contains all CLI commands for MCP Proxy Adapter.
|
|
5
|
+
|
|
6
|
+
Author: Vasiliy Zdanovskiy
|
|
7
|
+
email: vasilyvz@gmail.com
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .generate import GenerateCommand
|
|
11
|
+
from .testconfig import TestConfigCommand
|
|
12
|
+
from .server import ServerCommand
|
|
13
|
+
from .sets import SetsCommand
|
|
14
|
+
|
|
15
|
+
__all__ = ['GenerateCommand', 'TestConfigCommand', 'ServerCommand', 'SetsCommand']
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Client Command
|
|
3
|
+
|
|
4
|
+
Client CLI for calling health and JSON-RPC endpoints in various modes.
|
|
5
|
+
|
|
6
|
+
Author: Vasiliy Zdanovskiy
|
|
7
|
+
email: vasilyvz@gmail.com
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Dict, Optional
|
|
13
|
+
|
|
14
|
+
import requests
|
|
15
|
+
from mcp_proxy_adapter.client.proxy import ProxyClient
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _build_base_url(protocol: str, host: str, port: int) -> str:
|
|
19
|
+
scheme = "https" if protocol == "https" else "http"
|
|
20
|
+
return f"{scheme}://{host}:{port}"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _request_kwargs(protocol: str, token_header: Optional[str], token: Optional[str],
|
|
24
|
+
cert: Optional[str], key: Optional[str], ca: Optional[str]) -> Dict[str, Any]:
|
|
25
|
+
headers: Dict[str, str] = {"Content-Type": "application/json"}
|
|
26
|
+
if token_header and token:
|
|
27
|
+
headers[token_header] = token
|
|
28
|
+
|
|
29
|
+
kwargs: Dict[str, Any] = {"headers": headers, "timeout": 10}
|
|
30
|
+
|
|
31
|
+
if protocol == "https":
|
|
32
|
+
if cert and key:
|
|
33
|
+
kwargs["cert"] = (cert, key)
|
|
34
|
+
# For examples we allow self-signed; if CA provided, use it, otherwise disable verification
|
|
35
|
+
if ca:
|
|
36
|
+
kwargs["verify"] = str(Path(ca))
|
|
37
|
+
else:
|
|
38
|
+
kwargs["verify"] = False
|
|
39
|
+
|
|
40
|
+
return kwargs
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def client_command(args) -> int:
|
|
44
|
+
"""Dispatch client subcommands."""
|
|
45
|
+
protocol = args.protocol
|
|
46
|
+
host = args.host
|
|
47
|
+
port = args.port
|
|
48
|
+
base = _build_base_url(protocol, host, port)
|
|
49
|
+
kwargs = _request_kwargs(
|
|
50
|
+
protocol,
|
|
51
|
+
getattr(args, "token_header", None),
|
|
52
|
+
getattr(args, "token", None),
|
|
53
|
+
getattr(args, "cert", None),
|
|
54
|
+
getattr(args, "key", None),
|
|
55
|
+
getattr(args, "ca", None),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
if args.client_command == "health":
|
|
60
|
+
resp = requests.get(f"{base}/health", **kwargs)
|
|
61
|
+
print(json.dumps(resp.json(), ensure_ascii=False))
|
|
62
|
+
return 0 if resp.ok else 1
|
|
63
|
+
|
|
64
|
+
if args.client_command == "jsonrpc":
|
|
65
|
+
payload: Dict[str, Any] = {
|
|
66
|
+
"jsonrpc": "2.0",
|
|
67
|
+
"method": args.method,
|
|
68
|
+
"params": json.loads(args.params) if args.params else {},
|
|
69
|
+
"id": args.id,
|
|
70
|
+
}
|
|
71
|
+
resp = requests.post(f"{base}/api/jsonrpc", data=json.dumps(payload), **kwargs)
|
|
72
|
+
print(json.dumps(resp.json(), ensure_ascii=False))
|
|
73
|
+
return 0 if resp.ok else 1
|
|
74
|
+
|
|
75
|
+
if args.client_command == "proxy-register":
|
|
76
|
+
pc = ProxyClient(args.proxy_url)
|
|
77
|
+
res = pc.register(args.name, args.url, capabilities=args.capabilities or [], metadata=None)
|
|
78
|
+
print(json.dumps(res, ensure_ascii=False))
|
|
79
|
+
return 0
|
|
80
|
+
|
|
81
|
+
if args.client_command == "proxy-unregister":
|
|
82
|
+
pc = ProxyClient(args.proxy_url)
|
|
83
|
+
res = pc.unregister(args.name)
|
|
84
|
+
print(json.dumps(res, ensure_ascii=False))
|
|
85
|
+
return 0
|
|
86
|
+
|
|
87
|
+
if args.client_command == "proxy-list":
|
|
88
|
+
pc = ProxyClient(args.proxy_url)
|
|
89
|
+
res = pc.list_servers()
|
|
90
|
+
print(json.dumps(res, ensure_ascii=False))
|
|
91
|
+
return 0
|
|
92
|
+
|
|
93
|
+
print("Available: client health|jsonrpc")
|
|
94
|
+
return 1
|
|
95
|
+
|
|
96
|
+
except Exception as exc: # noqa: BLE001 (keep simple CLI handling)
|
|
97
|
+
print(f"❌ Client error: {exc}")
|
|
98
|
+
return 1
|
|
99
|
+
|
|
100
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
CLI command: config generate (Simple configuration generator)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from argparse import Namespace
|
|
11
|
+
|
|
12
|
+
from mcp_proxy_adapter.core.config.simple_config_generator import SimpleConfigGenerator
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def config_generate_command(args: Namespace) -> int:
|
|
16
|
+
generator = SimpleConfigGenerator()
|
|
17
|
+
out = generator.generate(protocol=args.protocol, with_proxy=args.with_proxy, out_path=args.out)
|
|
18
|
+
print(f"✅ Configuration generated: {out}")
|
|
19
|
+
return 0
|
|
20
|
+
|
|
21
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
CLI command: config validate (Simple configuration validation)
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
from argparse import Namespace
|
|
12
|
+
|
|
13
|
+
from mcp_proxy_adapter.core.config.simple_config import SimpleConfig
|
|
14
|
+
from mcp_proxy_adapter.core.config.simple_config_validator import SimpleConfigValidator
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def config_validate_command(args: Namespace) -> int:
|
|
18
|
+
cfg = SimpleConfig(args.file)
|
|
19
|
+
try:
|
|
20
|
+
model = cfg.load()
|
|
21
|
+
except Exception as e:
|
|
22
|
+
print(f"❌ Failed to load config: {e}")
|
|
23
|
+
return 1
|
|
24
|
+
|
|
25
|
+
validator = SimpleConfigValidator()
|
|
26
|
+
errors = validator.validate(model)
|
|
27
|
+
if errors:
|
|
28
|
+
print("❌ Validation failed:")
|
|
29
|
+
for err in errors:
|
|
30
|
+
print(f" - {err.message}")
|
|
31
|
+
return 1
|
|
32
|
+
|
|
33
|
+
print("✅ Validation OK")
|
|
34
|
+
return 0
|
|
35
|
+
|
|
36
|
+
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generate Command
|
|
3
|
+
|
|
4
|
+
This module implements the generate command for creating configuration files.
|
|
5
|
+
|
|
6
|
+
Author: Vasiliy Zdanovskiy
|
|
7
|
+
email: vasilyvz@gmail.com
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, Any, Optional
|
|
13
|
+
|
|
14
|
+
# Import the existing config generator
|
|
15
|
+
try:
|
|
16
|
+
from mcp_proxy_adapter.examples.config_builder import generate_complete_config
|
|
17
|
+
from mcp_proxy_adapter.core.config_validator import ConfigValidator
|
|
18
|
+
VALIDATION_AVAILABLE = True
|
|
19
|
+
except ImportError:
|
|
20
|
+
VALIDATION_AVAILABLE = False
|
|
21
|
+
print("Warning: Configuration validation not available. Install the package to enable validation.")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GenerateCommand:
|
|
25
|
+
"""Command for generating configuration files."""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
"""Initialize the generate command."""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
def execute(self, args: Dict[str, Any]) -> int:
|
|
32
|
+
"""
|
|
33
|
+
Execute the generate command.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
args: Parsed command arguments
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Exit code (0 for success, 1 for error)
|
|
40
|
+
"""
|
|
41
|
+
try:
|
|
42
|
+
# Handle special cases
|
|
43
|
+
if args.get('all'):
|
|
44
|
+
return self._generate_all_configs(args)
|
|
45
|
+
|
|
46
|
+
# Generate single configuration
|
|
47
|
+
return self._generate_single_config(args)
|
|
48
|
+
|
|
49
|
+
except Exception as e:
|
|
50
|
+
print(f"❌ Error generating configuration: {e}")
|
|
51
|
+
return 1
|
|
52
|
+
|
|
53
|
+
def _generate_single_config(self, args: Dict[str, Any]) -> int:
|
|
54
|
+
"""Generate a single configuration file."""
|
|
55
|
+
# Create configuration
|
|
56
|
+
config = self._create_config_from_args(args)
|
|
57
|
+
|
|
58
|
+
# Save configuration
|
|
59
|
+
if args.get('stdout'):
|
|
60
|
+
# Output to stdout
|
|
61
|
+
print(json.dumps(config, indent=2, ensure_ascii=False))
|
|
62
|
+
else:
|
|
63
|
+
# Save to file
|
|
64
|
+
config_file = self._save_config(config, args)
|
|
65
|
+
print(f"✅ Configuration saved to: {config_file}")
|
|
66
|
+
|
|
67
|
+
return 0
|
|
68
|
+
|
|
69
|
+
def _generate_all_configs(self, args: Dict[str, Any]) -> int:
|
|
70
|
+
"""Generate all standard configurations."""
|
|
71
|
+
print("🔧 Generating MCP Proxy Adapter configurations...")
|
|
72
|
+
print("=" * 60)
|
|
73
|
+
|
|
74
|
+
# Define all standard configurations
|
|
75
|
+
configs = [
|
|
76
|
+
# HTTP configurations
|
|
77
|
+
("http", False, False, 20000),
|
|
78
|
+
("http", True, True, 20001), # token + roles
|
|
79
|
+
("http", True, False, 20002), # token only
|
|
80
|
+
|
|
81
|
+
# HTTPS configurations
|
|
82
|
+
("https", False, False, 20003),
|
|
83
|
+
("https", True, True, 20004), # token + roles
|
|
84
|
+
("https", True, False, 20005), # token only
|
|
85
|
+
|
|
86
|
+
# mTLS configurations
|
|
87
|
+
("mtls", False, False, 20006),
|
|
88
|
+
("mtls", False, True, 20007), # roles only (from certificate)
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
generated_files = []
|
|
92
|
+
|
|
93
|
+
for protocol, token, roles, port in configs:
|
|
94
|
+
# Create configuration name
|
|
95
|
+
name_parts = [protocol]
|
|
96
|
+
if token:
|
|
97
|
+
name_parts.append("token")
|
|
98
|
+
if roles:
|
|
99
|
+
name_parts.append("roles")
|
|
100
|
+
|
|
101
|
+
config_name = "_".join(name_parts)
|
|
102
|
+
|
|
103
|
+
# Create args for this configuration
|
|
104
|
+
config_args = args.copy()
|
|
105
|
+
config_args.update({
|
|
106
|
+
'protocol': protocol,
|
|
107
|
+
'token': token,
|
|
108
|
+
'roles': roles,
|
|
109
|
+
'port': port
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
# Generate configuration
|
|
113
|
+
config = self._create_config_from_args(config_args)
|
|
114
|
+
|
|
115
|
+
# Save configuration
|
|
116
|
+
config_file = self._save_config(config, config_args, config_name)
|
|
117
|
+
generated_files.append(config_file)
|
|
118
|
+
|
|
119
|
+
print(f"✅ Created {config_name}.json (port {port})")
|
|
120
|
+
|
|
121
|
+
# Create roles.json file if any role-based configs were generated
|
|
122
|
+
self._create_roles_file(args.get('output_dir', './configs'))
|
|
123
|
+
|
|
124
|
+
print(f"\n🎉 Generated {len(generated_files)} configurations in {args.get('output_dir', './configs')}/")
|
|
125
|
+
print("\n📋 Generated configurations:")
|
|
126
|
+
for config_file in generated_files:
|
|
127
|
+
print(f" - {config_file.name}")
|
|
128
|
+
|
|
129
|
+
return 0
|
|
130
|
+
|
|
131
|
+
def _create_config_from_args(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
132
|
+
"""Create configuration dictionary from arguments."""
|
|
133
|
+
# Start with basic configuration
|
|
134
|
+
config = generate_complete_config(
|
|
135
|
+
args.get('host', '127.0.0.1'),
|
|
136
|
+
args.get('port', 8000)
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Set protocol
|
|
140
|
+
config["server"]["protocol"] = args.get('protocol', 'http')
|
|
141
|
+
|
|
142
|
+
# Configure SSL based on protocol
|
|
143
|
+
if args.get('protocol') == 'https':
|
|
144
|
+
config["ssl"]["enabled"] = True
|
|
145
|
+
config["ssl"]["cert_file"] = f"{args.get('cert_dir', './certs')}/server.crt"
|
|
146
|
+
config["ssl"]["key_file"] = f"{args.get('key_dir', './keys')}/server.key"
|
|
147
|
+
elif args.get('protocol') == 'mtls':
|
|
148
|
+
config["ssl"]["enabled"] = True
|
|
149
|
+
config["ssl"]["cert_file"] = f"{args.get('cert_dir', './certs')}/server.crt"
|
|
150
|
+
config["ssl"]["key_file"] = f"{args.get('key_dir', './keys')}/server.key"
|
|
151
|
+
config["ssl"]["ca_cert"] = f"{args.get('cert_dir', './certs')}/ca.crt"
|
|
152
|
+
config["transport"]["verify_client"] = True
|
|
153
|
+
|
|
154
|
+
# Configure security if token authentication is enabled
|
|
155
|
+
if args.get('token'):
|
|
156
|
+
config["security"]["enabled"] = True
|
|
157
|
+
config["security"]["tokens"] = {
|
|
158
|
+
"admin": "admin-secret-key",
|
|
159
|
+
"user": "user-secret-key",
|
|
160
|
+
"readonly": "readonly-secret-key"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if args.get('roles'):
|
|
164
|
+
config["security"]["roles"] = {
|
|
165
|
+
"admin": ["read", "write", "delete", "admin"],
|
|
166
|
+
"user": ["read", "write"],
|
|
167
|
+
"readonly": ["read"]
|
|
168
|
+
}
|
|
169
|
+
config["security"]["roles_file"] = f"{args.get('output_dir', './configs')}/roles.json"
|
|
170
|
+
config["roles"]["enabled"] = True
|
|
171
|
+
config["roles"]["config_file"] = f"{args.get('output_dir', './configs')}/roles.json"
|
|
172
|
+
elif args.get('roles') and args.get('protocol') == 'mtls':
|
|
173
|
+
# For mTLS, roles can be enabled without tokens (from certificate)
|
|
174
|
+
config["roles"]["enabled"] = True
|
|
175
|
+
config["roles"]["config_file"] = f"{args.get('output_dir', './configs')}/roles.json"
|
|
176
|
+
|
|
177
|
+
# Configure proxy registration if enabled
|
|
178
|
+
if args.get('proxy_url'):
|
|
179
|
+
config["proxy_registration"]["enabled"] = True
|
|
180
|
+
config["proxy_registration"]["proxy_url"] = args['proxy_url']
|
|
181
|
+
config["proxy_registration"]["server_id"] = args.get('server_id', 'mcp-proxy-adapter')
|
|
182
|
+
|
|
183
|
+
return config
|
|
184
|
+
|
|
185
|
+
def _save_config(self, config: Dict[str, Any], args: Dict[str, Any], filename: Optional[str] = None) -> Path:
|
|
186
|
+
"""Save configuration to file with optional validation."""
|
|
187
|
+
output_dir = Path(args.get('output_dir', './configs'))
|
|
188
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
189
|
+
|
|
190
|
+
# Determine filename
|
|
191
|
+
if filename:
|
|
192
|
+
config_name = filename
|
|
193
|
+
elif args.get('output'):
|
|
194
|
+
config_name = args['output']
|
|
195
|
+
else:
|
|
196
|
+
# Generate filename from arguments
|
|
197
|
+
name_parts = [args.get('protocol', 'http')]
|
|
198
|
+
if args.get('token'):
|
|
199
|
+
name_parts.append("token")
|
|
200
|
+
if args.get('roles'):
|
|
201
|
+
name_parts.append("roles")
|
|
202
|
+
config_name = "_".join(name_parts)
|
|
203
|
+
|
|
204
|
+
config_file = output_dir / f"{config_name}.json"
|
|
205
|
+
|
|
206
|
+
# Save configuration
|
|
207
|
+
with open(config_file, 'w', encoding='utf-8') as f:
|
|
208
|
+
json.dump(config, f, indent=2, ensure_ascii=False)
|
|
209
|
+
|
|
210
|
+
# Validate configuration if requested and validation is available
|
|
211
|
+
if not args.get('no_validate') and VALIDATION_AVAILABLE:
|
|
212
|
+
print(f"🔍 Validating configuration: {config_file}")
|
|
213
|
+
validator = ConfigValidator()
|
|
214
|
+
validator.config_data = config
|
|
215
|
+
results = validator.validate_config()
|
|
216
|
+
|
|
217
|
+
if results:
|
|
218
|
+
print("⚠️ Validation issues found:")
|
|
219
|
+
for result in results:
|
|
220
|
+
level_symbol = "❌" if result.level == "error" else "⚠️" if result.level == "warning" else "ℹ️"
|
|
221
|
+
print(f" {level_symbol} {result.message}")
|
|
222
|
+
if hasattr(result, 'suggestion') and result.suggestion:
|
|
223
|
+
print(f" Suggestion: {result.suggestion}")
|
|
224
|
+
else:
|
|
225
|
+
print("✅ Configuration validation passed!")
|
|
226
|
+
|
|
227
|
+
return config_file
|
|
228
|
+
|
|
229
|
+
def _create_roles_file(self, output_dir: str) -> None:
|
|
230
|
+
"""Create roles.json file for role-based configurations."""
|
|
231
|
+
roles_config = {
|
|
232
|
+
"enabled": True,
|
|
233
|
+
"default_policy": {
|
|
234
|
+
"deny_by_default": False,
|
|
235
|
+
"require_role_match": False,
|
|
236
|
+
"case_sensitive": False,
|
|
237
|
+
"allow_wildcard": False
|
|
238
|
+
},
|
|
239
|
+
"roles": {
|
|
240
|
+
"admin": ["read", "write", "delete", "admin"],
|
|
241
|
+
"user": ["read", "write"],
|
|
242
|
+
"readonly": ["read"],
|
|
243
|
+
"guest": ["read"],
|
|
244
|
+
"proxy": ["read", "write"]
|
|
245
|
+
},
|
|
246
|
+
"permissions": {
|
|
247
|
+
"read": ["GET"],
|
|
248
|
+
"write": ["POST", "PUT", "PATCH"],
|
|
249
|
+
"delete": ["DELETE"],
|
|
250
|
+
"admin": ["*"]
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
roles_file = Path(output_dir) / "roles.json"
|
|
255
|
+
with open(roles_file, 'w', encoding='utf-8') as f:
|
|
256
|
+
json.dump(roles_config, f, indent=2, ensure_ascii=False)
|
|
257
|
+
print(f"✅ Created roles.json")
|
|
258
|
+
|
|
259
|
+
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Server Command
|
|
3
|
+
|
|
4
|
+
This module implements the server command for starting MCP Proxy Adapter server.
|
|
5
|
+
|
|
6
|
+
Author: Vasiliy Zdanovskiy
|
|
7
|
+
email: vasilyvz@gmail.com
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Dict, Any
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from mcp_proxy_adapter.core.config_validator import ConfigValidator
|
|
16
|
+
from mcp_proxy_adapter.core.server_adapter import UnifiedServerRunner
|
|
17
|
+
from mcp_proxy_adapter.api.app import create_app
|
|
18
|
+
VALIDATION_AVAILABLE = True
|
|
19
|
+
except ImportError:
|
|
20
|
+
VALIDATION_AVAILABLE = False
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ServerCommand:
|
|
24
|
+
"""Command for starting the MCP Proxy Adapter server."""
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
"""Initialize the server command."""
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
def execute(self, args: Dict[str, Any]) -> int:
|
|
31
|
+
"""
|
|
32
|
+
Execute the server command.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
args: Parsed command arguments
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Exit code (0 for success, 1 for error)
|
|
39
|
+
"""
|
|
40
|
+
config_file = args['config']
|
|
41
|
+
no_validate = args.get('no_validate', False)
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
# Load configuration
|
|
45
|
+
print(f"🔍 Loading configuration from: {config_file}")
|
|
46
|
+
with open(config_file, 'r', encoding='utf-8') as f:
|
|
47
|
+
config = json.load(f)
|
|
48
|
+
|
|
49
|
+
# Validate configuration if not disabled
|
|
50
|
+
if not no_validate and VALIDATION_AVAILABLE:
|
|
51
|
+
print("🔍 Validating configuration...")
|
|
52
|
+
if not self._validate_config(config, config_file):
|
|
53
|
+
print("❌ Configuration validation failed. Server not started.")
|
|
54
|
+
return 1
|
|
55
|
+
print("✅ Configuration validation passed!")
|
|
56
|
+
elif no_validate:
|
|
57
|
+
print("⚠️ Configuration validation skipped (--no-validate)")
|
|
58
|
+
else:
|
|
59
|
+
print("⚠️ Configuration validation not available")
|
|
60
|
+
|
|
61
|
+
# Override configuration with command line arguments
|
|
62
|
+
if args.get('port'):
|
|
63
|
+
config['server']['port'] = args['port']
|
|
64
|
+
print(f"🔧 Overriding port to: {args['port']}")
|
|
65
|
+
|
|
66
|
+
if args.get('host'):
|
|
67
|
+
config['server']['host'] = args['host']
|
|
68
|
+
print(f"🔧 Overriding host to: {args['host']}")
|
|
69
|
+
|
|
70
|
+
# Create and start server
|
|
71
|
+
print("🚀 Starting MCP Proxy Adapter server...")
|
|
72
|
+
self._start_server(config, args)
|
|
73
|
+
|
|
74
|
+
except FileNotFoundError:
|
|
75
|
+
print(f"❌ Configuration file not found: {config_file}")
|
|
76
|
+
return 1
|
|
77
|
+
except json.JSONDecodeError as e:
|
|
78
|
+
print(f"❌ Invalid JSON in configuration file: {e}")
|
|
79
|
+
return 1
|
|
80
|
+
except Exception as e:
|
|
81
|
+
print(f"❌ Error starting server: {e}")
|
|
82
|
+
return 1
|
|
83
|
+
|
|
84
|
+
def _validate_config(self, config: Dict[str, Any], config_file: str) -> bool:
|
|
85
|
+
"""
|
|
86
|
+
Validate configuration using ConfigValidator.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
config: Configuration dictionary
|
|
90
|
+
config_file: Path to configuration file
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
True if configuration is valid, False otherwise
|
|
94
|
+
"""
|
|
95
|
+
try:
|
|
96
|
+
validator = ConfigValidator()
|
|
97
|
+
validator.config_data = config
|
|
98
|
+
results = validator.validate_config()
|
|
99
|
+
|
|
100
|
+
# Check for errors
|
|
101
|
+
errors = [r for r in results if r.level == "error"]
|
|
102
|
+
warnings = [r for r in results if r.level == "warning"]
|
|
103
|
+
|
|
104
|
+
if errors:
|
|
105
|
+
print("❌ Configuration validation errors:")
|
|
106
|
+
for error in errors:
|
|
107
|
+
print(f" • {error.message}")
|
|
108
|
+
if hasattr(error, 'suggestion') and error.suggestion:
|
|
109
|
+
print(f" → {error.suggestion}")
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
if warnings:
|
|
113
|
+
print("⚠️ Configuration validation warnings:")
|
|
114
|
+
for warning in warnings:
|
|
115
|
+
print(f" • {warning.message}")
|
|
116
|
+
if hasattr(warning, 'suggestion') and warning.suggestion:
|
|
117
|
+
print(f" → {warning.suggestion}")
|
|
118
|
+
|
|
119
|
+
return True
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
print(f"❌ Error during configuration validation: {e}")
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
def _start_server(self, config: Dict[str, Any], args: Dict[str, Any]) -> None:
|
|
126
|
+
"""
|
|
127
|
+
Start the MCP Proxy Adapter server.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
config: Server configuration
|
|
131
|
+
args: Command line arguments
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
# Create ASGI application
|
|
135
|
+
app = create_app(config)
|
|
136
|
+
|
|
137
|
+
# Prepare server configuration
|
|
138
|
+
server_config = {
|
|
139
|
+
'host': config['server']['host'],
|
|
140
|
+
'port': config['server']['port'],
|
|
141
|
+
'log_level': config['server'].get('log_level', 'INFO'),
|
|
142
|
+
'reload': args.get('reload', False)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Add SSL configuration if present
|
|
146
|
+
if 'ssl' in config and config['ssl'].get('enabled'):
|
|
147
|
+
server_config.update({
|
|
148
|
+
'certfile': config['ssl'].get('cert_file'),
|
|
149
|
+
'keyfile': config['ssl'].get('key_file'),
|
|
150
|
+
'ca_certs': config['ssl'].get('ca_cert'),
|
|
151
|
+
'verify_mode': 'CERT_REQUIRED' if config.get('transport', {}).get('verify_client') else 'CERT_NONE'
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
# Start server
|
|
155
|
+
print(f"🌐 Server starting on {server_config['host']}:{server_config['port']}")
|
|
156
|
+
print(f"📋 Protocol: {config['server']['protocol']}")
|
|
157
|
+
print(f"🔐 Security: {'Enabled' if config.get('security', {}).get('enabled') else 'Disabled'}")
|
|
158
|
+
print(f"🔑 Authentication: {'Token-based' if config.get('security', {}).get('tokens') else 'Certificate-based' if config['server']['protocol'] == 'mtls' else 'None'}")
|
|
159
|
+
print(f"👥 Roles: {'Enabled' if config.get('roles', {}).get('enabled') else 'Disabled'}")
|
|
160
|
+
print("=" * 60)
|
|
161
|
+
|
|
162
|
+
# Use UnifiedServerRunner to start the server
|
|
163
|
+
runner = UnifiedServerRunner()
|
|
164
|
+
runner.run_server(app, server_config)
|
|
165
|
+
|
|
166
|
+
except ImportError as e:
|
|
167
|
+
print(f"❌ Missing required dependencies: {e}")
|
|
168
|
+
print("💡 Install required packages: pip install hypercorn")
|
|
169
|
+
raise
|
|
170
|
+
except Exception as e:
|
|
171
|
+
print(f"❌ Failed to start server: {e}")
|
|
172
|
+
raise
|
|
173
|
+
|
|
174
|
+
|