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