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,608 @@
1
+ """
2
+ Universal Client for MCP Proxy Adapter Framework
3
+
4
+ This module provides a universal client that can connect to MCP Proxy Adapter servers
5
+ using various authentication methods and protocols. It's designed to be used for
6
+ proxy registration and general API communication.
7
+
8
+ Author: Vasiliy Zdanovskiy
9
+ email: vasilyvz@gmail.com
10
+ """
11
+
12
+ import asyncio
13
+ import json
14
+ import os
15
+ import ssl
16
+ import time
17
+ from pathlib import Path
18
+ from typing import Any, Dict, Optional
19
+ from urllib.parse import urljoin
20
+
21
+ import aiohttp
22
+ import requests
23
+
24
+ # Import security framework components
25
+ try:
26
+ from mcp_security_framework import (
27
+ SecurityManager,
28
+ AuthManager,
29
+ CertificateManager,
30
+ PermissionManager,
31
+ generate_api_key,
32
+ create_jwt_token,
33
+ validate_jwt_token,
34
+ extract_roles_from_cert,
35
+ validate_certificate_chain,
36
+ create_ssl_context,
37
+ validate_server_certificate,
38
+ )
39
+
40
+ SECURITY_FRAMEWORK_AVAILABLE = True
41
+ except ImportError:
42
+ SECURITY_FRAMEWORK_AVAILABLE = False
43
+ # Define stubs for missing imports
44
+ generate_api_key = None
45
+ create_jwt_token = None
46
+ validate_jwt_token = None
47
+ extract_roles_from_cert = None
48
+ validate_certificate_chain = None
49
+ create_ssl_context = None
50
+ validate_server_certificate = None
51
+
52
+
53
+ class UniversalClient:
54
+ """
55
+ Universal client that demonstrates all possible secure connection methods.
56
+
57
+ Supports:
58
+ - HTTP/HTTPS connections
59
+ - API Key authentication
60
+ - JWT token authentication
61
+ - Certificate-based authentication
62
+ - SSL/TLS with custom certificates
63
+ - Role-based access control
64
+ - Rate limiting awareness
65
+ """
66
+
67
+ def __init__(self, config: Dict[str, Any]):
68
+ """
69
+ Initialize universal client with configuration.
70
+
71
+ Args:
72
+ config: Client configuration with security settings
73
+ """
74
+ self.config = config
75
+ self.base_url = config.get("server_url", "http://localhost:8000")
76
+ self.timeout = config.get("timeout", 30)
77
+ self.retry_attempts = config.get("retry_attempts", 3)
78
+ self.retry_delay = config.get("retry_delay", 1)
79
+
80
+ # Security configuration
81
+ self.security_config = config.get("security", {})
82
+ self.auth_method = self.security_config.get("auth_method", "none")
83
+
84
+ # Initialize security managers if framework is available
85
+ self.security_manager = None
86
+ self.auth_manager = None
87
+ self.cert_manager = None
88
+
89
+ if SECURITY_FRAMEWORK_AVAILABLE:
90
+ self._initialize_security_managers()
91
+
92
+ # Session management
93
+ self.session: Optional[aiohttp.ClientSession] = None
94
+ self.current_token: Optional[str] = None
95
+ self.token_expiry: Optional[float] = None
96
+
97
+ print(f"Universal client initialized with auth method: {self.auth_method}")
98
+
99
+ def _initialize_security_managers(self) -> None:
100
+ """Initialize security framework managers."""
101
+ try:
102
+ # Initialize security manager
103
+ self.security_manager = SecurityManager(self.security_config)
104
+
105
+ # Initialize permission manager first
106
+ permissions_config = self.security_config.get("permissions", {})
107
+ self.permission_manager = PermissionManager(permissions_config)
108
+
109
+ # Initialize auth manager with permission_manager
110
+ auth_config = self.security_config.get("auth", {})
111
+ self.auth_manager = AuthManager(auth_config, self.permission_manager)
112
+
113
+ # Initialize certificate manager
114
+ cert_config = self.security_config.get("certificates", {})
115
+ self.cert_manager = CertificateManager(cert_config)
116
+
117
+ print("Security framework managers initialized successfully")
118
+ except Exception as e:
119
+ print(f"Warning: Failed to initialize security managers: {e}")
120
+
121
+ async def __aenter__(self):
122
+ """Async context manager entry."""
123
+ await self.connect()
124
+ return self
125
+
126
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
127
+ """Async context manager exit."""
128
+ await self.disconnect()
129
+
130
+ async def connect(self) -> None:
131
+ """Establish connection with authentication."""
132
+ print(
133
+ f"Connecting to {self.base_url} with {self.auth_method} authentication..."
134
+ )
135
+
136
+ # Create SSL context
137
+ ssl_context = self._create_ssl_context()
138
+
139
+ # Create connector with SSL context
140
+ connector = None
141
+ if ssl_context:
142
+ connector = aiohttp.TCPConnector(ssl=ssl_context)
143
+
144
+ # Create session
145
+ self.session = aiohttp.ClientSession(connector=connector)
146
+
147
+ # Perform authentication based on method
148
+ if self.auth_method == "api_key":
149
+ await self._authenticate_api_key()
150
+ elif self.auth_method == "jwt":
151
+ await self._authenticate_jwt()
152
+ elif self.auth_method == "certificate":
153
+ await self._authenticate_certificate()
154
+ elif self.auth_method == "basic":
155
+ await self._authenticate_basic()
156
+ else:
157
+ print("No authentication required")
158
+
159
+ print("Connection established successfully")
160
+
161
+ async def disconnect(self) -> None:
162
+ """Close connection and cleanup."""
163
+ if self.session:
164
+ await self.session.close()
165
+ self.session = None
166
+ print("Connection closed")
167
+
168
+ async def _authenticate_api_key(self) -> None:
169
+ """Authenticate using API key."""
170
+ api_key_config = self.security_config.get("api_key", {})
171
+ api_key = api_key_config.get("key")
172
+
173
+ if not api_key:
174
+ raise ValueError("API key not provided in configuration")
175
+
176
+ # Store API key for requests
177
+ self.current_token = api_key
178
+ print(f"Authenticated with API key: {api_key[:8]}...")
179
+
180
+ async def _authenticate_jwt(self) -> None:
181
+ """Authenticate using JWT token."""
182
+ jwt_config = self.security_config.get("jwt", {})
183
+
184
+ # Check if we have a stored token that's still valid
185
+ if self.current_token and self.token_expiry and time.time() < self.token_expiry:
186
+ print("Using existing JWT token")
187
+ return
188
+
189
+ # Get credentials for JWT
190
+ username = jwt_config.get("username")
191
+ password = jwt_config.get("password")
192
+ secret = jwt_config.get("secret")
193
+
194
+ if not all([username, password, secret]):
195
+ raise ValueError("JWT credentials not provided in configuration")
196
+
197
+ # Create JWT token
198
+ if SECURITY_FRAMEWORK_AVAILABLE:
199
+ self.current_token = create_jwt_token(
200
+ username, secret, expiry_hours=jwt_config.get("expiry_hours", 24)
201
+ )
202
+ else:
203
+ # Simple JWT creation (for demonstration)
204
+ import jwt
205
+
206
+ payload = {
207
+ "username": username,
208
+ "exp": time.time() + (jwt_config.get("expiry_hours", 24) * 3600),
209
+ }
210
+ self.current_token = jwt.encode(payload, secret, algorithm="HS256")
211
+
212
+ self.token_expiry = time.time() + (jwt_config.get("expiry_hours", 24) * 3600)
213
+ print(f"Authenticated with JWT token: {self.current_token[:20]}...")
214
+
215
+ async def _authenticate_certificate(self) -> None:
216
+ """Authenticate using client certificate."""
217
+ cert_config = self.security_config.get("certificate", {})
218
+
219
+ cert_file = cert_config.get("cert_file")
220
+ key_file = cert_config.get("key_file")
221
+
222
+ if not cert_file or not key_file:
223
+ raise ValueError("Certificate files not provided in configuration")
224
+
225
+ # Validate certificate
226
+ if SECURITY_FRAMEWORK_AVAILABLE and self.cert_manager:
227
+ try:
228
+ cert_info = self.cert_manager.validate_certificate(cert_file, key_file)
229
+ print(f"Certificate validated: {cert_info.get('subject', 'Unknown')}")
230
+
231
+ # Extract roles from certificate
232
+ roles = extract_roles_from_cert(cert_file)
233
+ if roles:
234
+ print(f"Certificate roles: {roles}")
235
+ except Exception as e:
236
+ print(f"Warning: Certificate validation failed: {e}")
237
+
238
+ print("Certificate authentication prepared")
239
+
240
+ async def _authenticate_basic(self) -> None:
241
+ """Authenticate using basic authentication."""
242
+ basic_config = self.security_config.get("basic", {})
243
+ username = basic_config.get("username")
244
+ password = basic_config.get("password")
245
+
246
+ if not username or not password:
247
+ raise ValueError("Basic auth credentials not provided in configuration")
248
+
249
+ import base64
250
+
251
+ credentials = base64.b64encode(f"{username}:{password}".encode()).decode()
252
+ self.current_token = f"Basic {credentials}"
253
+ print(f"Authenticated with basic auth: {username}")
254
+
255
+ def _get_auth_headers(self) -> Dict[str, str]:
256
+ """Get authentication headers for requests."""
257
+ headers = {"Content-Type": "application/json"}
258
+
259
+ if not self.current_token:
260
+ return headers
261
+
262
+ if self.auth_method == "api_key":
263
+ api_key_config = self.security_config.get("api_key", {})
264
+ header_name = api_key_config.get("header", "X-API-Key")
265
+ headers[header_name] = self.current_token
266
+ elif self.auth_method == "jwt":
267
+ headers["Authorization"] = f"Bearer {self.current_token}"
268
+ elif self.auth_method == "basic":
269
+ headers["Authorization"] = self.current_token
270
+
271
+ return headers
272
+
273
+ def _create_ssl_context(self) -> Optional[ssl.SSLContext]:
274
+ """Create SSL context for secure connections."""
275
+ ssl_config = self.security_config.get("ssl", {})
276
+ if not ssl_config.get("enabled", False):
277
+ return None
278
+
279
+ try:
280
+ context: Optional[ssl.SSLContext] = None
281
+
282
+ # Try security framework first
283
+ if self.security_manager:
284
+ try:
285
+ context = self.security_manager.create_client_ssl_context()
286
+ except Exception:
287
+ context = None
288
+
289
+ # Fallback SSL context creation
290
+ if context is None:
291
+ context = ssl.create_default_context()
292
+
293
+ # Always honor explicit client certificate config for mTLS
294
+ cert_config = self.security_config.get("certificate", {})
295
+ if cert_config.get("enabled", False):
296
+ cert_file = cert_config.get("cert_file")
297
+ key_file = cert_config.get("key_file")
298
+ if cert_file and key_file:
299
+ context.load_cert_chain(certfile=cert_file, keyfile=key_file)
300
+
301
+ # Add CA certificate if provided
302
+ ca_cert_file = ssl_config.get("ca_cert_file") or ssl_config.get("ca_cert")
303
+ if ca_cert_file and os.path.exists(ca_cert_file):
304
+ context.load_verify_locations(cafile=ca_cert_file)
305
+
306
+ # Configure verification
307
+ if ssl_config.get("check_hostname", True):
308
+ context.check_hostname = True
309
+ context.verify_mode = ssl.CERT_REQUIRED
310
+ else:
311
+ context.check_hostname = False
312
+ context.verify_mode = ssl.CERT_NONE
313
+
314
+ return context
315
+ except Exception as e:
316
+ print(f"Warning: Failed to create SSL context: {e}")
317
+ return None
318
+
319
+ async def request(
320
+ self,
321
+ method: str,
322
+ endpoint: str,
323
+ data: Optional[Dict[str, Any]] = None,
324
+ headers: Optional[Dict[str, str]] = None,
325
+ ) -> Dict[str, Any]:
326
+ """
327
+ Make authenticated request to server.
328
+
329
+ Args:
330
+ method: HTTP method (GET, POST, etc.)
331
+ endpoint: API endpoint
332
+ data: Request data
333
+ headers: Additional headers
334
+
335
+ Returns:
336
+ Response data
337
+ """
338
+ url = urljoin(self.base_url, endpoint)
339
+
340
+ # Prepare headers
341
+ request_headers = self._get_auth_headers()
342
+ if headers:
343
+ request_headers.update(headers)
344
+
345
+ try:
346
+ for attempt in range(self.retry_attempts):
347
+ try:
348
+ async with self.session.request(
349
+ method,
350
+ url,
351
+ json=data,
352
+ headers=request_headers,
353
+ timeout=aiohttp.ClientTimeout(total=self.timeout),
354
+ ) as response:
355
+ result = await response.json()
356
+
357
+ # Validate response if security framework available
358
+ if SECURITY_FRAMEWORK_AVAILABLE and self.security_manager:
359
+ self.security_manager.validate_server_response(
360
+ dict(response.headers)
361
+ )
362
+
363
+ if response.status >= 400:
364
+ print(
365
+ f"Request failed with status {response.status}: {result}"
366
+ )
367
+ return {"error": result, "status": response.status}
368
+
369
+ return result
370
+
371
+ except Exception as e:
372
+ print(f"Request attempt {attempt + 1} failed: {e}")
373
+ if attempt < self.retry_attempts - 1:
374
+ await asyncio.sleep(self.retry_delay)
375
+ else:
376
+ raise
377
+ except Exception as e:
378
+ print(f"Request failed: {e}")
379
+ raise
380
+
381
+ async def get(self, endpoint: str, **kwargs) -> Dict[str, Any]:
382
+ """Make GET request."""
383
+ return await self.request("GET", endpoint, **kwargs)
384
+
385
+ async def post(
386
+ self, endpoint: str, data: Dict[str, Any], **kwargs
387
+ ) -> Dict[str, Any]:
388
+ """Make POST request."""
389
+ return await self.request("POST", endpoint, data=data, **kwargs)
390
+
391
+ async def put(
392
+ self, endpoint: str, data: Dict[str, Any], **kwargs
393
+ ) -> Dict[str, Any]:
394
+ """Make PUT request."""
395
+ return await self.request("PUT", endpoint, data=data, **kwargs)
396
+
397
+ async def delete(self, endpoint: str, **kwargs) -> Dict[str, Any]:
398
+ """Make DELETE request."""
399
+ return await self.request("DELETE", endpoint, **kwargs)
400
+
401
+ async def test_connection(self) -> bool:
402
+ """Test connection to server."""
403
+ try:
404
+ result = await self.get("/health")
405
+ if "error" not in result:
406
+ print("✅ Connection test successful")
407
+ return True
408
+ else:
409
+ print(f"❌ Connection test failed: {result}")
410
+ return False
411
+ except Exception as e:
412
+ print(f"❌ Connection test failed: {e}")
413
+ return False
414
+
415
+ async def test_security_features(self) -> Dict[str, bool]:
416
+ """Test various security features."""
417
+ results = {}
418
+
419
+ # Test basic connectivity
420
+ results["connectivity"] = await self.test_connection()
421
+
422
+ # Test authentication
423
+ if self.auth_method != "none":
424
+ try:
425
+ result = await self.get("/api/auth/status")
426
+ results["authentication"] = "error" not in result
427
+ except:
428
+ results["authentication"] = False
429
+
430
+ # Test SSL/TLS
431
+ if self.base_url.startswith("https"):
432
+ results["ssl_tls"] = True
433
+ else:
434
+ results["ssl_tls"] = False
435
+
436
+ return results
437
+
438
+ async def register_proxy(self, proxy_config: Dict[str, Any]) -> Dict[str, Any]:
439
+ """
440
+ Register with proxy server.
441
+
442
+ Args:
443
+ proxy_config: Proxy registration configuration
444
+
445
+ Returns:
446
+ Registration result
447
+ """
448
+ try:
449
+ result = await self.post(
450
+ "/api/jsonrpc",
451
+ {
452
+ "jsonrpc": "2.0",
453
+ "method": "proxy_registration",
454
+ "params": proxy_config,
455
+ "id": 1,
456
+ },
457
+ )
458
+ return result
459
+ except Exception as e:
460
+ print(f"Proxy registration failed: {e}")
461
+ return {"error": str(e)}
462
+
463
+ async def execute_command(
464
+ self, command: str, params: Dict[str, Any] = None
465
+ ) -> Dict[str, Any]:
466
+ """
467
+ Execute a command on the server.
468
+
469
+ Args:
470
+ command: Command name
471
+ params: Command parameters
472
+
473
+ Returns:
474
+ Command result
475
+ """
476
+ try:
477
+ result = await self.post(
478
+ "/api/jsonrpc",
479
+ {"jsonrpc": "2.0", "method": command, "params": params or {}, "id": 1},
480
+ )
481
+ return result
482
+ except Exception as e:
483
+ print(f"Command execution failed: {e}")
484
+ return {"error": str(e)}
485
+
486
+
487
+ def create_client_from_config(config_file: str) -> UniversalClient:
488
+ """
489
+ Create a UniversalClient instance from a configuration file.
490
+
491
+ Args:
492
+ config_file: Path to configuration file
493
+
494
+ Returns:
495
+ UniversalClient instance
496
+ """
497
+ try:
498
+ with open(config_file, "r") as f:
499
+ config_data = json.load(f)
500
+
501
+ # Extract server configuration
502
+ server_config = config_data.get("server", {})
503
+ host = server_config.get("host", "127.0.0.1")
504
+ port = server_config.get("port", 8000)
505
+
506
+ # Determine protocol
507
+ ssl_config = config_data.get("ssl", {})
508
+ ssl_enabled = ssl_config.get("enabled", False)
509
+ protocol = "https" if ssl_enabled else "http"
510
+
511
+ server_url = f"{protocol}://{host}:{port}"
512
+
513
+ # Create client configuration
514
+ client_config = {
515
+ "server_url": server_url,
516
+ "timeout": 30,
517
+ "retry_attempts": 3,
518
+ "retry_delay": 1,
519
+ "security": {"auth_method": "none"},
520
+ }
521
+
522
+ # Add SSL configuration if needed
523
+ if ssl_enabled:
524
+ client_config["security"]["ssl"] = {
525
+ "enabled": True,
526
+ "check_hostname": False,
527
+ "verify": False,
528
+ }
529
+
530
+ # Add CA certificate if available
531
+ ca_cert = ssl_config.get("ca_cert")
532
+ if ca_cert and os.path.exists(ca_cert):
533
+ client_config["security"]["ssl"]["ca_cert_file"] = ca_cert
534
+
535
+ return UniversalClient(client_config)
536
+
537
+ except Exception as e:
538
+ raise ValueError(f"Failed to create client from config: {e}")
539
+
540
+
541
+ # CLI interface for standalone usage
542
+ async def main():
543
+ """Main function for CLI usage."""
544
+ import argparse
545
+
546
+ parser = argparse.ArgumentParser(
547
+ description="Universal Client for MCP Proxy Adapter"
548
+ )
549
+ parser.add_argument("--config", help="Path to configuration file")
550
+ parser.add_argument("--method", help="JSON-RPC method to call")
551
+ parser.add_argument("--params", help="JSON-RPC parameters (JSON string)")
552
+ parser.add_argument("--auth-method", help="Authentication method")
553
+ parser.add_argument("--server-url", help="Server URL")
554
+
555
+ args = parser.parse_args()
556
+
557
+ if args.config:
558
+ # Load configuration from file
559
+ try:
560
+ client = create_client_from_config(args.config)
561
+
562
+ print(f"🚀 Testing --config connection")
563
+ print("=" * 40)
564
+ print(f"Universal client initialized with auth method: --config")
565
+ print(f"Connecting to {client.base_url} with --config authentication...")
566
+
567
+ async with client:
568
+ # Test connection
569
+ success = await client.test_connection()
570
+
571
+ if success:
572
+ print("No authentication required")
573
+ print("Connection established successfully")
574
+
575
+ if args.method:
576
+ # Execute JSON-RPC method
577
+ params = {}
578
+ if args.params:
579
+ try:
580
+ params = json.loads(args.params)
581
+ except json.JSONDecodeError:
582
+ print("❌ Invalid JSON parameters")
583
+ return
584
+
585
+ result = await client.execute_command(args.method, params)
586
+ print(f"✅ Method '{args.method}' executed successfully:")
587
+ print(json.dumps(result, indent=2))
588
+ else:
589
+ # Default to help command
590
+ result = await client.execute_command("help")
591
+ print("✅ Help command executed successfully:")
592
+ print(json.dumps(result, indent=2))
593
+ else:
594
+ print("❌ Connection failed")
595
+ print("Connection closed")
596
+
597
+ except FileNotFoundError:
598
+ print(f"❌ Configuration file not found: {args.config}")
599
+ except json.JSONDecodeError:
600
+ print(f"❌ Invalid JSON in configuration file: {args.config}")
601
+ except Exception as e:
602
+ print(f"❌ Error loading configuration: {e}")
603
+ else:
604
+ print("❌ Configuration file required. Use --config option.")
605
+
606
+
607
+ if __name__ == "__main__":
608
+ asyncio.run(main())