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.

Files changed (269) hide show
  1. mcp_proxy_adapter/__init__.py +47 -0
  2. mcp_proxy_adapter/__main__.py +13 -0
  3. mcp_proxy_adapter/api/__init__.py +0 -0
  4. mcp_proxy_adapter/api/app.py +66 -0
  5. mcp_proxy_adapter/api/core/__init__.py +18 -0
  6. mcp_proxy_adapter/api/core/app_factory.py +400 -0
  7. mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
  8. mcp_proxy_adapter/api/core/registration_context.py +356 -0
  9. mcp_proxy_adapter/api/core/registration_manager.py +307 -0
  10. mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
  11. mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
  12. mcp_proxy_adapter/api/handlers.py +181 -0
  13. mcp_proxy_adapter/api/middleware/__init__.py +21 -0
  14. mcp_proxy_adapter/api/middleware/base.py +54 -0
  15. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
  16. mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
  17. mcp_proxy_adapter/api/middleware/factory.py +147 -0
  18. mcp_proxy_adapter/api/middleware/logging.py +31 -0
  19. mcp_proxy_adapter/api/middleware/performance.py +51 -0
  20. mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
  21. mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
  22. mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
  23. mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
  24. mcp_proxy_adapter/api/openapi/__init__.py +21 -0
  25. mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
  26. mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
  27. mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
  28. mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
  29. mcp_proxy_adapter/api/schemas.py +270 -0
  30. mcp_proxy_adapter/api/tool_integration.py +131 -0
  31. mcp_proxy_adapter/api/tools.py +163 -0
  32. mcp_proxy_adapter/cli/__init__.py +12 -0
  33. mcp_proxy_adapter/cli/commands/__init__.py +15 -0
  34. mcp_proxy_adapter/cli/commands/client.py +100 -0
  35. mcp_proxy_adapter/cli/commands/config_generate.py +105 -0
  36. mcp_proxy_adapter/cli/commands/config_validate.py +94 -0
  37. mcp_proxy_adapter/cli/commands/generate.py +259 -0
  38. mcp_proxy_adapter/cli/commands/server.py +174 -0
  39. mcp_proxy_adapter/cli/commands/sets.py +132 -0
  40. mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
  41. mcp_proxy_adapter/cli/examples/__init__.py +8 -0
  42. mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
  43. mcp_proxy_adapter/cli/examples/https_token.py +96 -0
  44. mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
  45. mcp_proxy_adapter/cli/main.py +63 -0
  46. mcp_proxy_adapter/cli/parser.py +338 -0
  47. mcp_proxy_adapter/cli/validators.py +231 -0
  48. mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
  49. mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
  50. mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
  51. mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
  52. mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
  53. mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
  54. mcp_proxy_adapter/client/proxy.py +123 -0
  55. mcp_proxy_adapter/commands/__init__.py +66 -0
  56. mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
  57. mcp_proxy_adapter/commands/base.py +389 -0
  58. mcp_proxy_adapter/commands/builtin_commands.py +30 -0
  59. mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
  60. mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
  61. mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
  62. mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
  63. mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
  64. mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
  65. mcp_proxy_adapter/commands/catalog_manager.py +97 -0
  66. mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
  67. mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
  68. mcp_proxy_adapter/commands/command_registry.py +298 -0
  69. mcp_proxy_adapter/commands/config_command.py +102 -0
  70. mcp_proxy_adapter/commands/dependency_container.py +40 -0
  71. mcp_proxy_adapter/commands/dependency_manager.py +143 -0
  72. mcp_proxy_adapter/commands/echo_command.py +48 -0
  73. mcp_proxy_adapter/commands/health_command.py +142 -0
  74. mcp_proxy_adapter/commands/help_command.py +175 -0
  75. mcp_proxy_adapter/commands/hooks.py +172 -0
  76. mcp_proxy_adapter/commands/key_management_command.py +484 -0
  77. mcp_proxy_adapter/commands/load_command.py +123 -0
  78. mcp_proxy_adapter/commands/plugins_command.py +246 -0
  79. mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
  80. mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
  81. mcp_proxy_adapter/commands/queue_commands.py +750 -0
  82. mcp_proxy_adapter/commands/registration_status_command.py +76 -0
  83. mcp_proxy_adapter/commands/registry/__init__.py +18 -0
  84. mcp_proxy_adapter/commands/registry/command_info.py +103 -0
  85. mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
  86. mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
  87. mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
  88. mcp_proxy_adapter/commands/reload_command.py +136 -0
  89. mcp_proxy_adapter/commands/result.py +157 -0
  90. mcp_proxy_adapter/commands/role_test_command.py +99 -0
  91. mcp_proxy_adapter/commands/roles_management_command.py +502 -0
  92. mcp_proxy_adapter/commands/security_command.py +472 -0
  93. mcp_proxy_adapter/commands/settings_command.py +113 -0
  94. mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
  95. mcp_proxy_adapter/commands/token_management_command.py +500 -0
  96. mcp_proxy_adapter/commands/transport_management_command.py +129 -0
  97. mcp_proxy_adapter/commands/unload_command.py +92 -0
  98. mcp_proxy_adapter/config.py +32 -0
  99. mcp_proxy_adapter/core/__init__.py +8 -0
  100. mcp_proxy_adapter/core/app_factory.py +560 -0
  101. mcp_proxy_adapter/core/app_runner.py +318 -0
  102. mcp_proxy_adapter/core/auth_validator.py +508 -0
  103. mcp_proxy_adapter/core/certificate/__init__.py +20 -0
  104. mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
  105. mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
  106. mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
  107. mcp_proxy_adapter/core/certificate/certificate_validator.py +481 -0
  108. mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
  109. mcp_proxy_adapter/core/certificate_utils.py +249 -0
  110. mcp_proxy_adapter/core/client.py +608 -0
  111. mcp_proxy_adapter/core/client_manager.py +271 -0
  112. mcp_proxy_adapter/core/client_security.py +411 -0
  113. mcp_proxy_adapter/core/config/__init__.py +18 -0
  114. mcp_proxy_adapter/core/config/config.py +237 -0
  115. mcp_proxy_adapter/core/config/config_factory.py +22 -0
  116. mcp_proxy_adapter/core/config/config_loader.py +66 -0
  117. mcp_proxy_adapter/core/config/feature_manager.py +31 -0
  118. mcp_proxy_adapter/core/config/simple_config.py +204 -0
  119. mcp_proxy_adapter/core/config/simple_config_generator.py +131 -0
  120. mcp_proxy_adapter/core/config/simple_config_validator.py +476 -0
  121. mcp_proxy_adapter/core/config_converter.py +252 -0
  122. mcp_proxy_adapter/core/config_validator.py +211 -0
  123. mcp_proxy_adapter/core/crl_utils.py +362 -0
  124. mcp_proxy_adapter/core/errors.py +276 -0
  125. mcp_proxy_adapter/core/job_manager.py +54 -0
  126. mcp_proxy_adapter/core/logging.py +250 -0
  127. mcp_proxy_adapter/core/mtls_asgi.py +140 -0
  128. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  129. mcp_proxy_adapter/core/mtls_proxy.py +229 -0
  130. mcp_proxy_adapter/core/mtls_server.py +154 -0
  131. mcp_proxy_adapter/core/protocol_manager.py +232 -0
  132. mcp_proxy_adapter/core/proxy/__init__.py +19 -0
  133. mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
  134. mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
  135. mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
  136. mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
  137. mcp_proxy_adapter/core/proxy_client.py +184 -0
  138. mcp_proxy_adapter/core/proxy_registration.py +80 -0
  139. mcp_proxy_adapter/core/role_utils.py +103 -0
  140. mcp_proxy_adapter/core/security_adapter.py +343 -0
  141. mcp_proxy_adapter/core/security_factory.py +96 -0
  142. mcp_proxy_adapter/core/security_integration.py +342 -0
  143. mcp_proxy_adapter/core/server_adapter.py +251 -0
  144. mcp_proxy_adapter/core/server_engine.py +217 -0
  145. mcp_proxy_adapter/core/settings.py +260 -0
  146. mcp_proxy_adapter/core/signal_handler.py +107 -0
  147. mcp_proxy_adapter/core/ssl_utils.py +161 -0
  148. mcp_proxy_adapter/core/transport_manager.py +153 -0
  149. mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
  150. mcp_proxy_adapter/core/utils.py +101 -0
  151. mcp_proxy_adapter/core/validation/__init__.py +21 -0
  152. mcp_proxy_adapter/core/validation/config_validator.py +219 -0
  153. mcp_proxy_adapter/core/validation/file_validator.py +131 -0
  154. mcp_proxy_adapter/core/validation/protocol_validator.py +205 -0
  155. mcp_proxy_adapter/core/validation/security_validator.py +140 -0
  156. mcp_proxy_adapter/core/validation/validation_result.py +27 -0
  157. mcp_proxy_adapter/custom_openapi.py +58 -0
  158. mcp_proxy_adapter/examples/__init__.py +16 -0
  159. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  160. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  161. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  162. mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
  163. mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
  164. mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
  165. mcp_proxy_adapter/examples/check_config.py +413 -0
  166. mcp_proxy_adapter/examples/client_usage_example.py +164 -0
  167. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  168. mcp_proxy_adapter/examples/config_builder.py +234 -0
  169. mcp_proxy_adapter/examples/config_cli.py +282 -0
  170. mcp_proxy_adapter/examples/create_test_configs.py +174 -0
  171. mcp_proxy_adapter/examples/debug_request_state.py +130 -0
  172. mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
  173. mcp_proxy_adapter/examples/demo_client.py +287 -0
  174. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  175. mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
  176. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
  177. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
  178. mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
  179. mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
  180. mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
  181. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
  182. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
  183. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
  184. mcp_proxy_adapter/examples/full_application/main.py +311 -0
  185. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +161 -0
  186. mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
  187. mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
  188. mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
  189. mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
  190. mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
  191. mcp_proxy_adapter/examples/generate_config.py +502 -0
  192. mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
  193. mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
  194. mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
  195. mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
  196. mcp_proxy_adapter/examples/queue_server_example.py +85 -0
  197. mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
  198. mcp_proxy_adapter/examples/required_certificates.py +208 -0
  199. mcp_proxy_adapter/examples/run_example.py +77 -0
  200. mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
  201. mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
  202. mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
  203. mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
  204. mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
  205. mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
  206. mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
  207. mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
  208. mcp_proxy_adapter/examples/security_test_client.py +72 -0
  209. mcp_proxy_adapter/examples/setup/__init__.py +24 -0
  210. mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
  211. mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
  212. mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
  213. mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
  214. mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
  215. mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
  216. mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
  217. mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
  218. mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
  219. mcp_proxy_adapter/examples/test_config.py +205 -0
  220. mcp_proxy_adapter/examples/test_config_builder.py +110 -0
  221. mcp_proxy_adapter/examples/test_examples.py +308 -0
  222. mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
  223. mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
  224. mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
  225. mcp_proxy_adapter/examples/universal_client.py +674 -0
  226. mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
  227. mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
  228. mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
  229. mcp_proxy_adapter/integrations/__init__.py +25 -0
  230. mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
  231. mcp_proxy_adapter/main.py +311 -0
  232. mcp_proxy_adapter/openapi.py +375 -0
  233. mcp_proxy_adapter/schemas/base_schema.json +114 -0
  234. mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
  235. mcp_proxy_adapter/schemas/roles.json +37 -0
  236. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  237. mcp_proxy_adapter/version.py +5 -0
  238. mcp_proxy_adapter-6.9.50.dist-info/METADATA +1088 -0
  239. mcp_proxy_adapter-6.9.50.dist-info/RECORD +242 -0
  240. {mcp_proxy_adapter-2.0.1.dist-info → mcp_proxy_adapter-6.9.50.dist-info}/WHEEL +1 -1
  241. mcp_proxy_adapter-6.9.50.dist-info/entry_points.txt +14 -0
  242. mcp_proxy_adapter-6.9.50.dist-info/top_level.txt +1 -0
  243. adapters/__init__.py +0 -16
  244. analyzers/__init__.py +0 -14
  245. analyzers/docstring_analyzer.py +0 -199
  246. analyzers/type_analyzer.py +0 -151
  247. cli/__init__.py +0 -12
  248. cli/__main__.py +0 -79
  249. cli/command_runner.py +0 -233
  250. dispatchers/__init__.py +0 -14
  251. dispatchers/base_dispatcher.py +0 -85
  252. dispatchers/json_rpc_dispatcher.py +0 -198
  253. generators/__init__.py +0 -14
  254. generators/endpoint_generator.py +0 -172
  255. generators/openapi_generator.py +0 -254
  256. generators/rest_api_generator.py +0 -207
  257. mcp_proxy_adapter-2.0.1.dist-info/METADATA +0 -272
  258. mcp_proxy_adapter-2.0.1.dist-info/RECORD +0 -28
  259. mcp_proxy_adapter-2.0.1.dist-info/licenses/LICENSE +0 -21
  260. mcp_proxy_adapter-2.0.1.dist-info/top_level.txt +0 -7
  261. openapi_schema/__init__.py +0 -38
  262. openapi_schema/command_registry.py +0 -312
  263. openapi_schema/rest_schema.py +0 -510
  264. openapi_schema/rpc_generator.py +0 -307
  265. openapi_schema/rpc_schema.py +0 -416
  266. validators/__init__.py +0 -14
  267. validators/base_validator.py +0 -23
  268. validators/docstring_validator.py +0 -75
  269. validators/metadata_validator.py +0 -76
@@ -0,0 +1,219 @@
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
+ from .validation_result import ValidationResult
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class ConfigValidator:
22
+ """
23
+ Comprehensive configuration validator for MCP Proxy Adapter.
24
+
25
+ Validates:
26
+ - Required sections and keys
27
+ - File existence for referenced files
28
+ - Feature flag dependencies
29
+ - Protocol-specific requirements
30
+ - Security configuration consistency
31
+ """
32
+
33
+ def __init__(self, config_path: Optional[str] = None):
34
+ """
35
+ Initialize configuration validator.
36
+
37
+ Args:
38
+ config_path: Path to configuration file (optional)
39
+ """
40
+ self.config_path = config_path
41
+ self.config_data: Dict[str, Any] = {}
42
+ self.validation_results: List[ValidationResult] = []
43
+
44
+ def load_config(self, config_path: Optional[str] = None) -> None:
45
+ """
46
+ Load configuration from file.
47
+
48
+ Args:
49
+ config_path: Path to configuration file
50
+ """
51
+ if config_path:
52
+ self.config_path = config_path
53
+
54
+ if not self.config_path:
55
+ raise ValueError("No configuration path provided")
56
+
57
+ try:
58
+ with open(self.config_path, 'r', encoding='utf-8') as f:
59
+ self.config_data = json.load(f)
60
+ logger.info(f"Configuration loaded from {self.config_path}")
61
+ except FileNotFoundError:
62
+ raise FileNotFoundError(f"Configuration file not found: {self.config_path}")
63
+ except json.JSONDecodeError as e:
64
+ raise ValueError(f"Invalid JSON in configuration file: {e}")
65
+ except Exception as e:
66
+ raise RuntimeError(f"Error loading configuration: {e}")
67
+
68
+ def validate_config(self, config_data: Optional[Dict[str, Any]] = None) -> List[ValidationResult]:
69
+ """
70
+ Validate configuration data.
71
+
72
+ Args:
73
+ config_data: Configuration data to validate (optional)
74
+
75
+ Returns:
76
+ List of validation results
77
+ """
78
+ if config_data is not None:
79
+ self.config_data = config_data
80
+
81
+ if not self.config_data:
82
+ raise ValueError("No configuration data to validate")
83
+
84
+ self.validation_results = []
85
+
86
+ # Initialize validators
87
+ file_validator = FileValidator(self.config_data)
88
+ security_validator = SecurityValidator(self.config_data)
89
+ protocol_validator = ProtocolValidator(self.config_data)
90
+
91
+ # Run all validations
92
+ protocol_validator._validate_server_section()
93
+ protocol_validator._validate_feature_flags()
94
+ protocol = self.config_data.get("server", {}).get("protocol", "http")
95
+ if protocol == "https":
96
+ protocol_validator._validate_https_requirements()
97
+ elif protocol == "mtls":
98
+ protocol_validator._validate_mtls_requirements()
99
+ self.validation_results.extend(protocol_validator.validation_results)
100
+
101
+ self.validation_results.extend(file_validator.validate_file_existence())
102
+ self.validation_results.extend(security_validator.validate_security_consistency())
103
+ self.validation_results.extend(security_validator.validate_ssl_configuration())
104
+ self.validation_results.extend(security_validator.validate_roles_configuration())
105
+ self.validation_results.extend(security_validator.validate_proxy_registration())
106
+
107
+ # Additional validations
108
+ self._validate_unknown_fields()
109
+ self._validate_uuid_format()
110
+
111
+ return self.validation_results
112
+
113
+ def validate_all(self, config_data: Optional[Dict[str, Any]] = None) -> List[ValidationResult]:
114
+ """
115
+ Validate all aspects of the configuration.
116
+
117
+ Args:
118
+ config_data: Configuration data to validate (optional)
119
+
120
+ Returns:
121
+ List of validation results
122
+ """
123
+ return self.validate_config(config_data)
124
+
125
+ def _validate_unknown_fields(self) -> None:
126
+ """Validate for unknown configuration fields."""
127
+ known_sections = {
128
+ "server", "protocols", "security", "ssl", "auth", "roles",
129
+ "logging", "commands", "proxy_registration", "transport"
130
+ }
131
+
132
+ for section in self.config_data.keys():
133
+ if section not in known_sections:
134
+ self.validation_results.append(ValidationResult(
135
+ level="warning",
136
+ message=f"Unknown configuration section: {section}",
137
+ section=section,
138
+ suggestion="Check if this section is needed or if it's a typo"
139
+ ))
140
+
141
+ def _validate_uuid_format(self) -> None:
142
+ """Validate UUID format in configuration."""
143
+ uuid_fields = ["server.server_id", "proxy_registration.server_id"]
144
+
145
+ for field in uuid_fields:
146
+ value = self._get_nested_value_safe(field)
147
+ if value and not self._is_valid_uuid4(str(value)):
148
+ self.validation_results.append(ValidationResult(
149
+ level="warning",
150
+ message=f"Invalid UUID format in {field}: {value}",
151
+ section=field.split(".")[0],
152
+ key=field.split(".")[1],
153
+ suggestion="Use a valid UUID4 format"
154
+ ))
155
+
156
+ def _is_valid_uuid4(self, uuid_str: str) -> bool:
157
+ """Check if string is a valid UUID4."""
158
+ import re
159
+ 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}$'
160
+ return bool(re.match(uuid_pattern, uuid_str, re.IGNORECASE))
161
+
162
+ def _get_nested_value_safe(self, key: str, default: Any = None) -> Any:
163
+ """Safely get a nested value from configuration."""
164
+ keys = key.split('.')
165
+ value = self.config_data
166
+
167
+ for k in keys:
168
+ if isinstance(value, dict) and k in value:
169
+ value = value[k]
170
+ else:
171
+ return default
172
+
173
+ return value
174
+
175
+ def get_validation_summary(self) -> Dict[str, Any]:
176
+ """
177
+ Get a summary of validation results.
178
+
179
+ Returns:
180
+ Dictionary with validation summary
181
+ """
182
+ error_count = sum(1 for r in self.validation_results if r.level == "error")
183
+ warning_count = sum(1 for r in self.validation_results if r.level == "warning")
184
+ info_count = sum(1 for r in self.validation_results if r.level == "info")
185
+
186
+ return {
187
+ "total_issues": len(self.validation_results),
188
+ "errors": error_count,
189
+ "warnings": warning_count,
190
+ "info": info_count,
191
+ "is_valid": error_count == 0
192
+ }
193
+
194
+ def print_validation_report(self) -> None:
195
+ """Print a formatted validation report."""
196
+ summary = self.get_validation_summary()
197
+
198
+ print(f"\\n📋 Configuration Validation Report")
199
+ print(f"{'=' * 40}")
200
+ print(f"Total issues: {summary['total_issues']}")
201
+ print(f"Errors: {summary['errors']}")
202
+ print(f"Warnings: {summary['warnings']}")
203
+ print(f"Info: {summary['info']}")
204
+ print(f"Valid: {'✅ Yes' if summary['is_valid'] else '❌ No'}")
205
+
206
+ if self.validation_results:
207
+ print(f"\\n📝 Issues:")
208
+ for i, result in enumerate(self.validation_results, 1):
209
+ level_icon = {"error": "❌", "warning": "⚠️", "info": "ℹ️"}[result.level]
210
+ print(f"{i:2d}. {level_icon} {result.message}")
211
+ if result.section:
212
+ print(f" Section: {result.section}")
213
+ if result.key:
214
+ print(f" Key: {result.key}")
215
+ if result.suggestion:
216
+ print(f" Suggestion: {result.suggestion}")
217
+ print()
218
+
219
+
@@ -0,0 +1,131 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ File validation utilities for MCP Proxy Adapter configuration validation.
6
+ """
7
+
8
+ import os
9
+ import ssl
10
+ from typing import Dict, Any, List
11
+
12
+ from .validation_result import ValidationResult
13
+
14
+
15
+ class FileValidator:
16
+ """Validator for file-related configuration settings."""
17
+
18
+ def __init__(self, config_data: Dict[str, Any]):
19
+ self.config_data = config_data
20
+ self.validation_results: List[ValidationResult] = []
21
+
22
+
23
+
24
+
25
+
26
+ def _get_nested_value_safe(self, key: str, default: Any = None) -> Any:
27
+ """Safely get a nested value from configuration."""
28
+ keys = key.split('.')
29
+ value = self.config_data
30
+
31
+ for k in keys:
32
+ if isinstance(value, dict) and k in value:
33
+ value = value[k]
34
+ else:
35
+ return default
36
+
37
+ return value
38
+
39
+ def _has_nested_key(self, key: str) -> bool:
40
+ """Check if a nested key exists in configuration."""
41
+ keys = key.split('.')
42
+ value = self.config_data
43
+
44
+ for k in keys:
45
+ if isinstance(value, dict) and k in value:
46
+ value = value[k]
47
+ else:
48
+ return False
49
+
50
+ return True
51
+
52
+ def _is_file_required_for_enabled_features(self, file_key: str) -> bool:
53
+ """Check if a file is required based on enabled features."""
54
+ # SSL files are required if SSL is enabled
55
+ if file_key.startswith("ssl.") or file_key.startswith("transport.ssl."):
56
+ return self._get_nested_value_safe("ssl.enabled", False)
57
+
58
+ # Proxy registration files are required if proxy registration is enabled
59
+ if file_key.startswith("proxy_registration."):
60
+ return self._get_nested_value_safe("proxy_registration.enabled", False)
61
+
62
+ # Log directory is required if logging is enabled
63
+ if file_key == "logging.log_dir":
64
+ return self._get_nested_value_safe("logging.enabled", True)
65
+
66
+ # Command directories are required if commands are enabled
67
+ if file_key.startswith("commands."):
68
+ return self._get_nested_value_safe("commands.enabled", True)
69
+
70
+ # Security files are required if security is enabled
71
+ if file_key.startswith("security."):
72
+ return self._get_nested_value_safe("security.enabled", False)
73
+
74
+ return False
75
+
76
+ def validate_file_existence(self) -> List[ValidationResult]:
77
+ """
78
+ Validate that referenced files exist.
79
+
80
+ Returns:
81
+ List of validation results
82
+ """
83
+ self.validation_results = []
84
+
85
+ # Check SSL certificate files if SSL is enabled
86
+ if self._get_nested_value_safe("ssl.enabled", False):
87
+ cert_file = self._get_nested_value_safe("ssl.cert_file")
88
+ key_file = self._get_nested_value_safe("ssl.key_file")
89
+
90
+ if cert_file and not os.path.exists(cert_file):
91
+ self.validation_results.append(ValidationResult(
92
+ level="error",
93
+ message=f"SSL certificate file not found: {cert_file}",
94
+ section="ssl",
95
+ key="cert_file",
96
+ suggestion=f"Create or fix path to certificate file"
97
+ ))
98
+
99
+ if key_file and not os.path.exists(key_file):
100
+ self.validation_results.append(ValidationResult(
101
+ level="error",
102
+ message=f"SSL key file not found: {key_file}",
103
+ section="ssl",
104
+ key="key_file",
105
+ suggestion=f"Create or fix path to key file"
106
+ ))
107
+
108
+ # Check proxy registration certificate files if proxy registration is enabled
109
+ if self._get_nested_value_safe("proxy_registration.enabled", False):
110
+ proxy_cert = self._get_nested_value_safe("proxy_registration.certificate.cert_file")
111
+ proxy_key = self._get_nested_value_safe("proxy_registration.certificate.key_file")
112
+
113
+ if proxy_cert and not os.path.exists(proxy_cert):
114
+ self.validation_results.append(ValidationResult(
115
+ level="warning",
116
+ message=f"Proxy registration certificate file not found: {proxy_cert}",
117
+ section="proxy_registration.certificate",
118
+ key="cert_file",
119
+ suggestion=f"Create or fix path to certificate file"
120
+ ))
121
+
122
+ if proxy_key and not os.path.exists(proxy_key):
123
+ self.validation_results.append(ValidationResult(
124
+ level="warning",
125
+ message=f"Proxy registration key file not found: {proxy_key}",
126
+ section="proxy_registration.certificate",
127
+ key="key_file",
128
+ suggestion=f"Create or fix path to key file"
129
+ ))
130
+
131
+ return self.validation_results
@@ -0,0 +1,205 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Protocol validation utilities for MCP Proxy Adapter configuration validation.
6
+ """
7
+
8
+ import re
9
+ from typing import Dict, List, Any
10
+
11
+ from .validation_result import ValidationResult
12
+
13
+
14
+ class ProtocolValidator:
15
+ """Validator for protocol-related configuration settings."""
16
+
17
+ def __init__(self, config_data: Dict[str, Any]):
18
+ self.config_data = config_data
19
+ self.validation_results: List[ValidationResult] = []
20
+
21
+ def _validate_https_requirements(self) -> None:
22
+ """Validate HTTPS-specific requirements."""
23
+ # Check server section for certificates (SimpleConfig format)
24
+ server_config = self._get_nested_value_safe("server", {})
25
+
26
+ # Check for required SSL files in server section
27
+ if not server_config.get("cert_file"):
28
+ self.validation_results.append(
29
+ ValidationResult(
30
+ level="error",
31
+ message="HTTPS protocol requires SSL certificate file",
32
+ section="server",
33
+ key="cert_file",
34
+ suggestion="Specify server.cert_file",
35
+ )
36
+ )
37
+
38
+ if not server_config.get("key_file"):
39
+ self.validation_results.append(
40
+ ValidationResult(
41
+ level="error",
42
+ message="HTTPS protocol requires SSL key file",
43
+ section="server",
44
+ key="key_file",
45
+ suggestion="Specify server.key_file",
46
+ )
47
+ )
48
+
49
+ def _validate_mtls_requirements(self) -> None:
50
+ """Validate mTLS-specific requirements."""
51
+ # mTLS requires HTTPS
52
+ self._validate_https_requirements()
53
+
54
+ # Check server section for certificates (SimpleConfig format)
55
+ server_config = self._get_nested_value_safe("server", {})
56
+ transport_config = self._get_nested_value_safe("transport", {})
57
+
58
+ # For mTLS server, we need:
59
+ # - Server cert/key (already checked by _validate_https_requirements)
60
+ # - CA cert for verifying client certificates
61
+ # - verify_client enabled
62
+
63
+ # Check for CA certificate (needed for client certificate verification)
64
+ if not server_config.get("ca_cert_file"):
65
+ self.validation_results.append(
66
+ ValidationResult(
67
+ level="error",
68
+ message="mTLS protocol requires CA certificate for client verification",
69
+ section="server",
70
+ key="ca_cert_file",
71
+ suggestion="Specify server.ca_cert_file for client certificate verification",
72
+ )
73
+ )
74
+
75
+ # Check for client verification
76
+ if not transport_config.get("verify_client", False):
77
+ self.validation_results.append(
78
+ ValidationResult(
79
+ level="warning",
80
+ message="mTLS protocol should have client verification enabled",
81
+ section="transport",
82
+ key="verify_client",
83
+ suggestion="Set transport.verify_client to true",
84
+ )
85
+ )
86
+
87
+ # Note: client_cert and client_key are NOT required for mTLS server
88
+ # They are only needed for client/registration configuration when connecting TO a proxy
89
+
90
+ def _validate_feature_flags(self) -> None:
91
+ """Validate feature flags based on protocol."""
92
+ protocol = self._get_nested_value_safe("server.protocol", "http")
93
+ server_config = self._get_nested_value_safe("server", {})
94
+
95
+ # Check if features are compatible with protocol
96
+ if protocol == "http":
97
+ # HTTP doesn't support SSL features
98
+ if server_config.get("cert_file") or server_config.get("key_file"):
99
+ self.validation_results.append(
100
+ ValidationResult(
101
+ level="warning",
102
+ message="SSL certificates are configured but protocol is HTTP. Consider using HTTPS",
103
+ section="server",
104
+ suggestion="Change protocol to https or remove certificate configuration",
105
+ )
106
+ )
107
+
108
+ # Check transport configuration
109
+ transport_config = self._get_nested_value_safe("transport", {})
110
+ if transport_config:
111
+ verify_client = transport_config.get("verify_client", False)
112
+ if verify_client and protocol == "http":
113
+ self.validation_results.append(
114
+ ValidationResult(
115
+ level="warning",
116
+ message="Client verification is enabled but protocol is HTTP",
117
+ section="transport",
118
+ key="verify_client",
119
+ suggestion="Change protocol to https or mtls, or disable client verification",
120
+ )
121
+ )
122
+
123
+ def _validate_server_section(self) -> None:
124
+ """Validate server section requirements."""
125
+ server_config = self.config_data.get("server", {})
126
+
127
+ # Check required fields
128
+ if "host" not in server_config:
129
+ self.validation_results.append(
130
+ ValidationResult(
131
+ level="error",
132
+ message="Server host is required",
133
+ section="server",
134
+ key="host",
135
+ suggestion="Add host field to server section",
136
+ )
137
+ )
138
+
139
+ if "port" not in server_config:
140
+ self.validation_results.append(
141
+ ValidationResult(
142
+ level="error",
143
+ message="Server port is required",
144
+ section="server",
145
+ key="port",
146
+ suggestion="Add port field to server section",
147
+ )
148
+ )
149
+
150
+ # Validate port number
151
+ port = server_config.get("port")
152
+ if port is not None:
153
+ if not isinstance(port, int) or not (1 <= port <= 65535):
154
+ self.validation_results.append(
155
+ ValidationResult(
156
+ level="error",
157
+ message=f"Invalid port number: {port}. Must be between 1 and 65535",
158
+ section="server",
159
+ key="port",
160
+ )
161
+ )
162
+
163
+ # Validate host format
164
+ host = server_config.get("host")
165
+ if host is not None:
166
+ if not self._is_valid_host(host):
167
+ self.validation_results.append(
168
+ ValidationResult(
169
+ level="error",
170
+ message=f"Invalid host format: {host}",
171
+ section="server",
172
+ key="host",
173
+ suggestion="Use a valid hostname or IP address",
174
+ )
175
+ )
176
+
177
+ def _is_valid_host(self, host: str) -> bool:
178
+ """Check if host has valid format."""
179
+ # Check for localhost
180
+ if host in ["localhost", "127.0.0.1", "::1", "0.0.0.0"]:
181
+ return True
182
+
183
+ # Check for IP address
184
+ ip_pattern = r"^(\d{1,3}\.){3}\d{1,3}$"
185
+ if re.match(ip_pattern, host):
186
+ # Validate IP address ranges
187
+ parts = host.split(".")
188
+ return all(0 <= int(part) <= 255 for part in parts)
189
+
190
+ # Check for hostname (basic validation)
191
+ hostname_pattern = r"^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$"
192
+ return bool(re.match(hostname_pattern, host))
193
+
194
+ def _get_nested_value_safe(self, key: str, default: Any = None) -> Any:
195
+ """Safely get a nested value from configuration."""
196
+ keys = key.split(".")
197
+ value = self.config_data
198
+
199
+ for k in keys:
200
+ if isinstance(value, dict) and k in value:
201
+ value = value[k]
202
+ else:
203
+ return default
204
+
205
+ return value
@@ -0,0 +1,140 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Security validation utilities for MCP Proxy Adapter configuration validation.
6
+ """
7
+
8
+ import os
9
+ from typing import Dict, List, Any
10
+
11
+ from .validation_result import ValidationResult
12
+
13
+
14
+ class SecurityValidator:
15
+ """Validator for security-related configuration settings."""
16
+
17
+ def __init__(self, config_data: Dict[str, Any]):
18
+ self.config_data = config_data
19
+ self.validation_results: List[ValidationResult] = []
20
+
21
+
22
+
23
+
24
+
25
+ def _get_nested_value_safe(self, key: str, default: Any = None) -> Any:
26
+ """Safely get a nested value from configuration."""
27
+ keys = key.split('.')
28
+ value = self.config_data
29
+
30
+ for k in keys:
31
+ if isinstance(value, dict) and k in value:
32
+ value = value[k]
33
+ else:
34
+ return default
35
+
36
+ return value
37
+
38
+ def _has_nested_key(self, key: str) -> bool:
39
+ """Check if a nested key exists in configuration."""
40
+ keys = key.split('.')
41
+ value = self.config_data
42
+
43
+ for k in keys:
44
+ if isinstance(value, dict) and k in value:
45
+ value = value[k]
46
+ else:
47
+ return False
48
+
49
+ return True
50
+
51
+ def _is_valid_url(self, url: str) -> bool:
52
+ """Check if URL has valid format."""
53
+ try:
54
+ from urllib.parse import urlparse
55
+ parsed = urlparse(url)
56
+ return bool(parsed.scheme and parsed.netloc)
57
+ except Exception:
58
+ return False
59
+
60
+ def validate_security_consistency(self) -> List[ValidationResult]:
61
+ """
62
+ Validate security configuration consistency.
63
+
64
+ Returns:
65
+ List of validation results
66
+ """
67
+ self.validation_results = []
68
+ # Basic consistency checks can be added here
69
+ return self.validation_results
70
+
71
+ def validate_ssl_configuration(self) -> List[ValidationResult]:
72
+ """
73
+ Validate SSL configuration.
74
+
75
+ Returns:
76
+ List of validation results
77
+ """
78
+ self.validation_results = []
79
+
80
+ ssl_config = self._get_nested_value_safe("ssl", {})
81
+ if ssl_config.get("enabled", False):
82
+ if not ssl_config.get("cert_file"):
83
+ self.validation_results.append(ValidationResult(
84
+ level="error",
85
+ message="SSL is enabled but cert_file is not specified",
86
+ section="ssl",
87
+ key="cert_file",
88
+ suggestion="Specify ssl.cert_file"
89
+ ))
90
+ if not ssl_config.get("key_file"):
91
+ self.validation_results.append(ValidationResult(
92
+ level="error",
93
+ message="SSL is enabled but key_file is not specified",
94
+ section="ssl",
95
+ key="key_file",
96
+ suggestion="Specify ssl.key_file"
97
+ ))
98
+
99
+ return self.validation_results
100
+
101
+ def validate_roles_configuration(self) -> List[ValidationResult]:
102
+ """
103
+ Validate roles configuration.
104
+
105
+ Returns:
106
+ List of validation results
107
+ """
108
+ self.validation_results = []
109
+ # Roles validation can be added here
110
+ return self.validation_results
111
+
112
+ def validate_proxy_registration(self) -> List[ValidationResult]:
113
+ """
114
+ Validate proxy registration configuration.
115
+
116
+ Returns:
117
+ List of validation results
118
+ """
119
+ self.validation_results = []
120
+
121
+ proxy_config = self._get_nested_value_safe("proxy_registration", {})
122
+ if proxy_config.get("enabled", False):
123
+ if not proxy_config.get("proxy_url"):
124
+ self.validation_results.append(ValidationResult(
125
+ level="error",
126
+ message="Proxy registration is enabled but proxy_url is not specified",
127
+ section="proxy_registration",
128
+ key="proxy_url",
129
+ suggestion="Specify proxy_registration.proxy_url"
130
+ ))
131
+ elif not self._is_valid_url(proxy_config.get("proxy_url", "")):
132
+ self.validation_results.append(ValidationResult(
133
+ level="error",
134
+ message=f"Invalid proxy URL format: {proxy_config.get('proxy_url')}",
135
+ section="proxy_registration",
136
+ key="proxy_url",
137
+ suggestion="Use a valid URL format (e.g., http://host:port)"
138
+ ))
139
+
140
+ return self.validation_results