mcp-proxy-adapter 2.0.1__py3-none-any.whl ā 6.9.50__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +47 -0
- mcp_proxy_adapter/__main__.py +13 -0
- mcp_proxy_adapter/api/__init__.py +0 -0
- mcp_proxy_adapter/api/app.py +66 -0
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +400 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_context.py +356 -0
- mcp_proxy_adapter/api/core/registration_manager.py +307 -0
- mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +181 -0
- mcp_proxy_adapter/api/middleware/__init__.py +21 -0
- mcp_proxy_adapter/api/middleware/base.py +54 -0
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
- mcp_proxy_adapter/api/middleware/factory.py +147 -0
- mcp_proxy_adapter/api/middleware/logging.py +31 -0
- mcp_proxy_adapter/api/middleware/performance.py +51 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +270 -0
- mcp_proxy_adapter/api/tool_integration.py +131 -0
- mcp_proxy_adapter/api/tools.py +163 -0
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +105 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +94 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +132 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +338 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
- mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
- mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
- mcp_proxy_adapter/client/proxy.py +123 -0
- mcp_proxy_adapter/commands/__init__.py +66 -0
- mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
- mcp_proxy_adapter/commands/base.py +389 -0
- mcp_proxy_adapter/commands/builtin_commands.py +30 -0
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +97 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
- mcp_proxy_adapter/commands/command_registry.py +298 -0
- mcp_proxy_adapter/commands/config_command.py +102 -0
- mcp_proxy_adapter/commands/dependency_container.py +40 -0
- mcp_proxy_adapter/commands/dependency_manager.py +143 -0
- mcp_proxy_adapter/commands/echo_command.py +48 -0
- mcp_proxy_adapter/commands/health_command.py +142 -0
- mcp_proxy_adapter/commands/help_command.py +175 -0
- mcp_proxy_adapter/commands/hooks.py +172 -0
- mcp_proxy_adapter/commands/key_management_command.py +484 -0
- mcp_proxy_adapter/commands/load_command.py +123 -0
- mcp_proxy_adapter/commands/plugins_command.py +246 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +76 -0
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +136 -0
- mcp_proxy_adapter/commands/result.py +157 -0
- mcp_proxy_adapter/commands/role_test_command.py +99 -0
- mcp_proxy_adapter/commands/roles_management_command.py +502 -0
- mcp_proxy_adapter/commands/security_command.py +472 -0
- mcp_proxy_adapter/commands/settings_command.py +113 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
- mcp_proxy_adapter/commands/token_management_command.py +500 -0
- mcp_proxy_adapter/commands/transport_management_command.py +129 -0
- mcp_proxy_adapter/commands/unload_command.py +92 -0
- mcp_proxy_adapter/config.py +32 -0
- mcp_proxy_adapter/core/__init__.py +8 -0
- mcp_proxy_adapter/core/app_factory.py +560 -0
- mcp_proxy_adapter/core/app_runner.py +318 -0
- mcp_proxy_adapter/core/auth_validator.py +508 -0
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +481 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
- mcp_proxy_adapter/core/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/client.py +608 -0
- mcp_proxy_adapter/core/client_manager.py +271 -0
- mcp_proxy_adapter/core/client_security.py +411 -0
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +237 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +204 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +131 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +476 -0
- mcp_proxy_adapter/core/config_converter.py +252 -0
- mcp_proxy_adapter/core/config_validator.py +211 -0
- mcp_proxy_adapter/core/crl_utils.py +362 -0
- mcp_proxy_adapter/core/errors.py +276 -0
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +250 -0
- mcp_proxy_adapter/core/mtls_asgi.py +140 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/mtls_proxy.py +229 -0
- mcp_proxy_adapter/core/mtls_server.py +154 -0
- mcp_proxy_adapter/core/protocol_manager.py +232 -0
- mcp_proxy_adapter/core/proxy/__init__.py +19 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +184 -0
- mcp_proxy_adapter/core/proxy_registration.py +80 -0
- mcp_proxy_adapter/core/role_utils.py +103 -0
- mcp_proxy_adapter/core/security_adapter.py +343 -0
- mcp_proxy_adapter/core/security_factory.py +96 -0
- mcp_proxy_adapter/core/security_integration.py +342 -0
- mcp_proxy_adapter/core/server_adapter.py +251 -0
- mcp_proxy_adapter/core/server_engine.py +217 -0
- mcp_proxy_adapter/core/settings.py +260 -0
- mcp_proxy_adapter/core/signal_handler.py +107 -0
- mcp_proxy_adapter/core/ssl_utils.py +161 -0
- mcp_proxy_adapter/core/transport_manager.py +153 -0
- mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
- mcp_proxy_adapter/core/utils.py +101 -0
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +219 -0
- mcp_proxy_adapter/core/validation/file_validator.py +131 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +205 -0
- mcp_proxy_adapter/core/validation/security_validator.py +140 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +58 -0
- mcp_proxy_adapter/examples/__init__.py +16 -0
- mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
- mcp_proxy_adapter/examples/check_config.py +413 -0
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/config_builder.py +234 -0
- mcp_proxy_adapter/examples/config_cli.py +282 -0
- mcp_proxy_adapter/examples/create_test_configs.py +174 -0
- mcp_proxy_adapter/examples/debug_request_state.py +130 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
- mcp_proxy_adapter/examples/demo_client.py +287 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
- mcp_proxy_adapter/examples/full_application/main.py +311 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +161 -0
- mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
- mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
- mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
- mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
- mcp_proxy_adapter/examples/generate_config.py +502 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +208 -0
- mcp_proxy_adapter/examples/run_example.py +77 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +72 -0
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
- mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
- mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
- mcp_proxy_adapter/examples/test_config.py +205 -0
- mcp_proxy_adapter/examples/test_config_builder.py +110 -0
- mcp_proxy_adapter/examples/test_examples.py +308 -0
- mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
- mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
- mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
- mcp_proxy_adapter/examples/universal_client.py +674 -0
- mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +311 -0
- mcp_proxy_adapter/openapi.py +375 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/schemas/roles.json +37 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/version.py +5 -0
- mcp_proxy_adapter-6.9.50.dist-info/METADATA +1088 -0
- mcp_proxy_adapter-6.9.50.dist-info/RECORD +242 -0
- {mcp_proxy_adapter-2.0.1.dist-info ā mcp_proxy_adapter-6.9.50.dist-info}/WHEEL +1 -1
- mcp_proxy_adapter-6.9.50.dist-info/entry_points.txt +14 -0
- mcp_proxy_adapter-6.9.50.dist-info/top_level.txt +1 -0
- adapters/__init__.py +0 -16
- analyzers/__init__.py +0 -14
- analyzers/docstring_analyzer.py +0 -199
- analyzers/type_analyzer.py +0 -151
- cli/__init__.py +0 -12
- cli/__main__.py +0 -79
- cli/command_runner.py +0 -233
- dispatchers/__init__.py +0 -14
- dispatchers/base_dispatcher.py +0 -85
- dispatchers/json_rpc_dispatcher.py +0 -198
- generators/__init__.py +0 -14
- generators/endpoint_generator.py +0 -172
- generators/openapi_generator.py +0 -254
- generators/rest_api_generator.py +0 -207
- mcp_proxy_adapter-2.0.1.dist-info/METADATA +0 -272
- mcp_proxy_adapter-2.0.1.dist-info/RECORD +0 -28
- mcp_proxy_adapter-2.0.1.dist-info/licenses/LICENSE +0 -21
- mcp_proxy_adapter-2.0.1.dist-info/top_level.txt +0 -7
- openapi_schema/__init__.py +0 -38
- openapi_schema/command_registry.py +0 -312
- openapi_schema/rest_schema.py +0 -510
- openapi_schema/rpc_generator.py +0 -307
- openapi_schema/rpc_schema.py +0 -416
- validators/__init__.py +0 -14
- validators/base_validator.py +0 -23
- validators/docstring_validator.py +0 -75
- validators/metadata_validator.py +0 -76
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Configuration Converter for security framework integration.
|
|
3
|
+
|
|
4
|
+
This module provides utilities to convert between mcp_proxy_adapter configuration
|
|
5
|
+
format and mcp_security_framework configuration format, ensuring backward compatibility.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
from typing import Dict, Any, Optional
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConfigConverter:
|
|
17
|
+
"""
|
|
18
|
+
Converter for configuration formats.
|
|
19
|
+
|
|
20
|
+
Provides methods to convert between mcp_proxy_adapter configuration
|
|
21
|
+
and mcp_security_framework configuration formats.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def to_security_framework_config(mcp_config: Dict[str, Any]) -> Dict[str, Any]:
|
|
26
|
+
"""
|
|
27
|
+
Convert mcp_proxy_adapter configuration to SecurityConfig format.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
mcp_config: mcp_proxy_adapter configuration dictionary
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
SecurityConfig compatible dictionary
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
# Start with default security framework config
|
|
37
|
+
security_config = {
|
|
38
|
+
"auth": {
|
|
39
|
+
"enabled": True,
|
|
40
|
+
"methods": ["api_key"],
|
|
41
|
+
"api_keys": {},
|
|
42
|
+
"jwt_secret": "",
|
|
43
|
+
"jwt_algorithm": "HS256",
|
|
44
|
+
},
|
|
45
|
+
"ssl": {
|
|
46
|
+
"enabled": False,
|
|
47
|
+
"cert_file": None,
|
|
48
|
+
"key_file": None,
|
|
49
|
+
"ca_cert": None,
|
|
50
|
+
"min_tls_version": "TLSv1.2",
|
|
51
|
+
"verify_client": False,
|
|
52
|
+
"client_cert_required": False,
|
|
53
|
+
},
|
|
54
|
+
"permissions": {
|
|
55
|
+
"enabled": True,
|
|
56
|
+
"roles_file": "roles.json",
|
|
57
|
+
"default_role": "user",
|
|
58
|
+
"deny_by_default": True,
|
|
59
|
+
},
|
|
60
|
+
"rate_limit": {
|
|
61
|
+
"enabled": True,
|
|
62
|
+
"requests_per_minute": 60,
|
|
63
|
+
"requests_per_hour": 1000,
|
|
64
|
+
"burst_limit": 10,
|
|
65
|
+
"by_ip": True,
|
|
66
|
+
"by_user": True,
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Convert from security section if exists
|
|
71
|
+
if "security" in mcp_config:
|
|
72
|
+
security_section = mcp_config["security"]
|
|
73
|
+
|
|
74
|
+
# Convert auth config
|
|
75
|
+
if "auth" in security_section:
|
|
76
|
+
auth_config = security_section["auth"]
|
|
77
|
+
security_config["auth"].update(
|
|
78
|
+
{
|
|
79
|
+
"enabled": auth_config.get("enabled", True),
|
|
80
|
+
"methods": auth_config.get("methods", ["api_key"]),
|
|
81
|
+
"api_keys": auth_config.get("api_keys", {}),
|
|
82
|
+
"jwt_secret": auth_config.get("jwt_secret", ""),
|
|
83
|
+
"jwt_algorithm": auth_config.get("jwt_algorithm", "HS256"),
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Convert SSL config
|
|
88
|
+
if "ssl" in security_section:
|
|
89
|
+
ssl_config = security_section["ssl"]
|
|
90
|
+
security_config["ssl"].update(
|
|
91
|
+
{
|
|
92
|
+
"enabled": ssl_config.get("enabled", False),
|
|
93
|
+
"cert_file": ssl_config.get("cert_file"),
|
|
94
|
+
"key_file": ssl_config.get("key_file"),
|
|
95
|
+
"ca_cert": ssl_config.get("ca_cert"),
|
|
96
|
+
"min_tls_version": ssl_config.get(
|
|
97
|
+
"min_tls_version", "TLSv1.2"
|
|
98
|
+
),
|
|
99
|
+
"verify_client": ssl_config.get("verify_client", False),
|
|
100
|
+
"client_cert_required": ssl_config.get(
|
|
101
|
+
"client_cert_required", False
|
|
102
|
+
),
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Convert permissions config
|
|
107
|
+
if "permissions" in security_section:
|
|
108
|
+
permissions_config = security_section["permissions"]
|
|
109
|
+
security_config["permissions"].update(
|
|
110
|
+
{
|
|
111
|
+
"enabled": permissions_config.get("enabled", True),
|
|
112
|
+
"roles_file": permissions_config.get(
|
|
113
|
+
"roles_file", "roles.json"
|
|
114
|
+
),
|
|
115
|
+
"default_role": permissions_config.get(
|
|
116
|
+
"default_role", "user"
|
|
117
|
+
),
|
|
118
|
+
"deny_by_default": permissions_config.get(
|
|
119
|
+
"deny_by_default", True
|
|
120
|
+
),
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# Convert rate limit config
|
|
125
|
+
if "rate_limit" in security_section:
|
|
126
|
+
rate_limit_config = security_section["rate_limit"]
|
|
127
|
+
security_config["rate_limit"].update(
|
|
128
|
+
{
|
|
129
|
+
"enabled": rate_limit_config.get("enabled", True),
|
|
130
|
+
"requests_per_minute": rate_limit_config.get(
|
|
131
|
+
"requests_per_minute", 60
|
|
132
|
+
),
|
|
133
|
+
"requests_per_hour": rate_limit_config.get(
|
|
134
|
+
"requests_per_hour", 1000
|
|
135
|
+
),
|
|
136
|
+
"burst_limit": rate_limit_config.get("burst_limit", 10),
|
|
137
|
+
"by_ip": rate_limit_config.get("by_ip", True),
|
|
138
|
+
"by_user": rate_limit_config.get("by_user", True),
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Convert from legacy SSL config if security section doesn't exist
|
|
143
|
+
elif "ssl" in mcp_config:
|
|
144
|
+
ssl_config = mcp_config["ssl"]
|
|
145
|
+
security_config["ssl"].update(
|
|
146
|
+
{
|
|
147
|
+
"enabled": ssl_config.get("enabled", False),
|
|
148
|
+
"cert_file": ssl_config.get("cert_file"),
|
|
149
|
+
"key_file": ssl_config.get("key_file"),
|
|
150
|
+
"ca_cert": ssl_config.get("ca_cert"),
|
|
151
|
+
"min_tls_version": ssl_config.get("min_tls_version", "TLSv1.2"),
|
|
152
|
+
"verify_client": ssl_config.get("verify_client", False),
|
|
153
|
+
"client_cert_required": ssl_config.get(
|
|
154
|
+
"client_cert_required", False
|
|
155
|
+
),
|
|
156
|
+
}
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Extract API keys from legacy SSL config
|
|
160
|
+
if "api_keys" in ssl_config:
|
|
161
|
+
security_config["auth"]["api_keys"] = ssl_config["api_keys"]
|
|
162
|
+
|
|
163
|
+
# Convert from legacy roles config
|
|
164
|
+
if "roles" in mcp_config:
|
|
165
|
+
roles_config = mcp_config["roles"]
|
|
166
|
+
security_config["permissions"].update(
|
|
167
|
+
{
|
|
168
|
+
"enabled": roles_config.get("enabled", True),
|
|
169
|
+
"roles_file": roles_config.get("config_file", "roles.json"),
|
|
170
|
+
"default_role": "user",
|
|
171
|
+
"deny_by_default": roles_config.get("default_policy", {}).get(
|
|
172
|
+
"deny_by_default", True
|
|
173
|
+
),
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
get_global_logger().info(
|
|
178
|
+
"Configuration converted to security framework format successfully"
|
|
179
|
+
)
|
|
180
|
+
return security_config
|
|
181
|
+
|
|
182
|
+
except Exception as e:
|
|
183
|
+
get_global_logger().error(
|
|
184
|
+
f"Failed to convert configuration to security framework format: {e}"
|
|
185
|
+
)
|
|
186
|
+
return ConfigConverter._get_default_security_config()
|
|
187
|
+
|
|
188
|
+
@staticmethod
|
|
189
|
+
|
|
190
|
+
@staticmethod
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
|
|
194
|
+
@staticmethod
|
|
195
|
+
def _get_default_security_config() -> Dict[str, Any]:
|
|
196
|
+
"""
|
|
197
|
+
Get default security framework configuration.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Default security framework configuration
|
|
201
|
+
"""
|
|
202
|
+
return {
|
|
203
|
+
"auth": {
|
|
204
|
+
"enabled": True,
|
|
205
|
+
"methods": ["api_key"],
|
|
206
|
+
"api_keys": {},
|
|
207
|
+
"jwt_secret": "",
|
|
208
|
+
"jwt_algorithm": "HS256",
|
|
209
|
+
},
|
|
210
|
+
"ssl": {
|
|
211
|
+
"enabled": False,
|
|
212
|
+
"cert_file": None,
|
|
213
|
+
"key_file": None,
|
|
214
|
+
"ca_cert": None,
|
|
215
|
+
"min_tls_version": "TLSv1.2",
|
|
216
|
+
"verify_client": False,
|
|
217
|
+
"client_cert_required": False,
|
|
218
|
+
},
|
|
219
|
+
"permissions": {
|
|
220
|
+
"enabled": True,
|
|
221
|
+
"roles_file": "roles.json",
|
|
222
|
+
"default_role": "user",
|
|
223
|
+
"deny_by_default": True,
|
|
224
|
+
},
|
|
225
|
+
"rate_limit": {
|
|
226
|
+
"enabled": True,
|
|
227
|
+
"requests_per_minute": 60,
|
|
228
|
+
"requests_per_hour": 1000,
|
|
229
|
+
"burst_limit": 10,
|
|
230
|
+
"by_ip": True,
|
|
231
|
+
"by_user": True,
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@staticmethod
|
|
236
|
+
def _get_default_mcp_config() -> Dict[str, Any]:
|
|
237
|
+
"""
|
|
238
|
+
Get default mcp_proxy_adapter configuration.
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Default mcp_proxy_adapter configuration
|
|
242
|
+
"""
|
|
243
|
+
return {
|
|
244
|
+
"security": {
|
|
245
|
+
"framework": "mcp_security_framework",
|
|
246
|
+
"enabled": True,
|
|
247
|
+
"auth": {"enabled": True, "methods": ["api_key"], "api_keys": {}},
|
|
248
|
+
"ssl": {"enabled": False, "cert_file": None, "key_file": None},
|
|
249
|
+
"permissions": {"enabled": True, "roles_file": "roles.json"},
|
|
250
|
+
"rate_limit": {"enabled": True, "requests_per_minute": 60},
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Vasiliy Zdanovskiy
|
|
3
|
+
email: vasilyvz@gmail.com
|
|
4
|
+
|
|
5
|
+
Main configuration validator for MCP Proxy Adapter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Dict, List, Any, Optional
|
|
12
|
+
|
|
13
|
+
from .file_validator import FileValidator
|
|
14
|
+
from .security_validator import SecurityValidator
|
|
15
|
+
from .protocol_validator import ProtocolValidator
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConfigValidator:
|
|
21
|
+
"""
|
|
22
|
+
Comprehensive configuration validator for MCP Proxy Adapter.
|
|
23
|
+
|
|
24
|
+
Validates:
|
|
25
|
+
- Required sections and keys
|
|
26
|
+
- File existence for referenced files
|
|
27
|
+
- Feature flag dependencies
|
|
28
|
+
- Protocol-specific requirements
|
|
29
|
+
- Security configuration consistency
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, config_path: Optional[str] = None):
|
|
33
|
+
"""
|
|
34
|
+
Initialize configuration validator.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
config_path: Path to configuration file (optional)
|
|
38
|
+
"""
|
|
39
|
+
self.config_path = config_path
|
|
40
|
+
self.config_data: Dict[str, Any] = {}
|
|
41
|
+
self.validation_results: List[ValidationResult] = []
|
|
42
|
+
|
|
43
|
+
def load_config(self, config_path: Optional[str] = None) -> None:
|
|
44
|
+
"""
|
|
45
|
+
Load configuration from file.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
config_path: Path to configuration file
|
|
49
|
+
"""
|
|
50
|
+
if config_path:
|
|
51
|
+
self.config_path = config_path
|
|
52
|
+
|
|
53
|
+
if not self.config_path:
|
|
54
|
+
raise ValueError("No configuration path provided")
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
with open(self.config_path, 'r', encoding='utf-8') as f:
|
|
58
|
+
self.config_data = json.load(f)
|
|
59
|
+
logger.info(f"Configuration loaded from {self.config_path}")
|
|
60
|
+
except FileNotFoundError:
|
|
61
|
+
raise FileNotFoundError(f"Configuration file not found: {self.config_path}")
|
|
62
|
+
except json.JSONDecodeError as e:
|
|
63
|
+
raise ValueError(f"Invalid JSON in configuration file: {e}")
|
|
64
|
+
except Exception as e:
|
|
65
|
+
raise RuntimeError(f"Error loading configuration: {e}")
|
|
66
|
+
|
|
67
|
+
def validate_config(self, config_data: Optional[Dict[str, Any]] = None) -> List[ValidationResult]:
|
|
68
|
+
"""
|
|
69
|
+
Validate configuration data.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
config_data: Configuration data to validate (optional)
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
List of validation results
|
|
76
|
+
"""
|
|
77
|
+
if config_data is not None:
|
|
78
|
+
self.config_data = config_data
|
|
79
|
+
|
|
80
|
+
if not self.config_data:
|
|
81
|
+
raise ValueError("No configuration data to validate")
|
|
82
|
+
|
|
83
|
+
self.validation_results = []
|
|
84
|
+
|
|
85
|
+
# Initialize validators
|
|
86
|
+
file_validator = FileValidator(self.config_data)
|
|
87
|
+
security_validator = SecurityValidator(self.config_data)
|
|
88
|
+
protocol_validator = ProtocolValidator(self.config_data)
|
|
89
|
+
|
|
90
|
+
# Run all validations
|
|
91
|
+
self.validation_results.extend(protocol_validator.validate_required_sections())
|
|
92
|
+
self.validation_results.extend(protocol_validator.validate_protocol_requirements())
|
|
93
|
+
self.validation_results.extend(file_validator.validate_file_existence())
|
|
94
|
+
self.validation_results.extend(security_validator.validate_security_consistency())
|
|
95
|
+
self.validation_results.extend(security_validator.validate_ssl_configuration())
|
|
96
|
+
self.validation_results.extend(security_validator.validate_roles_configuration())
|
|
97
|
+
self.validation_results.extend(security_validator.validate_proxy_registration())
|
|
98
|
+
|
|
99
|
+
# Additional validations
|
|
100
|
+
self._validate_unknown_fields()
|
|
101
|
+
self._validate_uuid_format()
|
|
102
|
+
|
|
103
|
+
return self.validation_results
|
|
104
|
+
|
|
105
|
+
def validate_all(self, config_data: Optional[Dict[str, Any]] = None) -> List[ValidationResult]:
|
|
106
|
+
"""
|
|
107
|
+
Validate all aspects of the configuration.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
config_data: Configuration data to validate (optional)
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
List of validation results
|
|
114
|
+
"""
|
|
115
|
+
return self.validate_config(config_data)
|
|
116
|
+
|
|
117
|
+
def _validate_unknown_fields(self) -> None:
|
|
118
|
+
"""Validate for unknown configuration fields."""
|
|
119
|
+
known_sections = {
|
|
120
|
+
"server", "protocols", "security", "ssl", "auth", "roles",
|
|
121
|
+
"logging", "commands", "proxy_registration", "transport"
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for section in self.config_data.keys():
|
|
125
|
+
if section not in known_sections:
|
|
126
|
+
self.validation_results.append(ValidationResult(
|
|
127
|
+
level="warning",
|
|
128
|
+
message=f"Unknown configuration section: {section}",
|
|
129
|
+
section=section,
|
|
130
|
+
suggestion="Check if this section is needed or if it's a typo"
|
|
131
|
+
))
|
|
132
|
+
|
|
133
|
+
def _validate_uuid_format(self) -> None:
|
|
134
|
+
"""Validate UUID format in configuration."""
|
|
135
|
+
uuid_fields = ["server.server_id", "proxy_registration.server_id"]
|
|
136
|
+
|
|
137
|
+
for field in uuid_fields:
|
|
138
|
+
value = self._get_nested_value_safe(field)
|
|
139
|
+
if value and not self._is_valid_uuid4(str(value)):
|
|
140
|
+
self.validation_results.append(ValidationResult(
|
|
141
|
+
level="warning",
|
|
142
|
+
message=f"Invalid UUID format in {field}: {value}",
|
|
143
|
+
section=field.split(".")[0],
|
|
144
|
+
key=field.split(".")[1],
|
|
145
|
+
suggestion="Use a valid UUID4 format"
|
|
146
|
+
))
|
|
147
|
+
|
|
148
|
+
def _is_valid_uuid4(self, uuid_str: str) -> bool:
|
|
149
|
+
"""Check if string is a valid UUID4."""
|
|
150
|
+
import re
|
|
151
|
+
uuid_pattern = r'^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'
|
|
152
|
+
return bool(re.match(uuid_pattern, uuid_str, re.IGNORECASE))
|
|
153
|
+
|
|
154
|
+
def _get_nested_value_safe(self, key: str, default: Any = None) -> Any:
|
|
155
|
+
"""Safely get a nested value from configuration."""
|
|
156
|
+
keys = key.split('.')
|
|
157
|
+
value = self.config_data
|
|
158
|
+
|
|
159
|
+
for k in keys:
|
|
160
|
+
if isinstance(value, dict) and k in value:
|
|
161
|
+
value = value[k]
|
|
162
|
+
else:
|
|
163
|
+
return default
|
|
164
|
+
|
|
165
|
+
return value
|
|
166
|
+
|
|
167
|
+
def get_validation_summary(self) -> Dict[str, Any]:
|
|
168
|
+
"""
|
|
169
|
+
Get a summary of validation results.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
Dictionary with validation summary
|
|
173
|
+
"""
|
|
174
|
+
error_count = sum(1 for r in self.validation_results if r.level == "error")
|
|
175
|
+
warning_count = sum(1 for r in self.validation_results if r.level == "warning")
|
|
176
|
+
info_count = sum(1 for r in self.validation_results if r.level == "info")
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
"total_issues": len(self.validation_results),
|
|
180
|
+
"errors": error_count,
|
|
181
|
+
"warnings": warning_count,
|
|
182
|
+
"info": info_count,
|
|
183
|
+
"is_valid": error_count == 0
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
def print_validation_report(self) -> None:
|
|
187
|
+
"""Print a formatted validation report."""
|
|
188
|
+
summary = self.get_validation_summary()
|
|
189
|
+
|
|
190
|
+
print(f"\\nš Configuration Validation Report")
|
|
191
|
+
print(f"{'=' * 40}")
|
|
192
|
+
print(f"Total issues: {summary['total_issues']}")
|
|
193
|
+
print(f"Errors: {summary['errors']}")
|
|
194
|
+
print(f"Warnings: {summary['warnings']}")
|
|
195
|
+
print(f"Info: {summary['info']}")
|
|
196
|
+
print(f"Valid: {'ā
Yes' if summary['is_valid'] else 'ā No'}")
|
|
197
|
+
|
|
198
|
+
if self.validation_results:
|
|
199
|
+
print(f"\\nš Issues:")
|
|
200
|
+
for i, result in enumerate(self.validation_results, 1):
|
|
201
|
+
level_icon = {"error": "ā", "warning": "ā ļø", "info": "ā¹ļø"}[result.level]
|
|
202
|
+
print(f"{i:2d}. {level_icon} {result.message}")
|
|
203
|
+
if result.section:
|
|
204
|
+
print(f" Section: {result.section}")
|
|
205
|
+
if result.key:
|
|
206
|
+
print(f" Key: {result.key}")
|
|
207
|
+
if result.suggestion:
|
|
208
|
+
print(f" Suggestion: {result.suggestion}")
|
|
209
|
+
print()
|
|
210
|
+
|
|
211
|
+
|