mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.1.0__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.
Files changed (259) hide show
  1. mcp_proxy_adapter/api/app.py +174 -80
  2. mcp_proxy_adapter/api/handlers.py +16 -5
  3. mcp_proxy_adapter/api/middleware/__init__.py +7 -2
  4. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  5. mcp_proxy_adapter/api/middleware/factory.py +36 -12
  6. mcp_proxy_adapter/api/middleware/unified_security.py +152 -0
  7. mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
  8. mcp_proxy_adapter/commands/__init__.py +7 -1
  9. mcp_proxy_adapter/commands/base.py +7 -4
  10. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  11. mcp_proxy_adapter/commands/command_registry.py +8 -0
  12. mcp_proxy_adapter/commands/echo_command.py +81 -0
  13. mcp_proxy_adapter/commands/help_command.py +21 -14
  14. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  15. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  16. mcp_proxy_adapter/commands/security_command.py +488 -0
  17. mcp_proxy_adapter/commands/ssl_setup_command.py +2 -2
  18. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  19. mcp_proxy_adapter/config.py +81 -21
  20. mcp_proxy_adapter/core/app_factory.py +326 -0
  21. mcp_proxy_adapter/core/client_security.py +384 -0
  22. mcp_proxy_adapter/core/logging.py +8 -3
  23. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  24. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  25. mcp_proxy_adapter/core/protocol_manager.py +9 -0
  26. mcp_proxy_adapter/core/proxy_client.py +602 -0
  27. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  28. mcp_proxy_adapter/core/security_adapter.py +12 -15
  29. mcp_proxy_adapter/core/security_integration.py +277 -0
  30. mcp_proxy_adapter/core/server_adapter.py +345 -0
  31. mcp_proxy_adapter/core/server_engine.py +364 -0
  32. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  33. mcp_proxy_adapter/examples/README.md +230 -97
  34. mcp_proxy_adapter/examples/README_EN.md +258 -0
  35. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  36. mcp_proxy_adapter/examples/__pycache__/security_configurations.cpython-312.pyc +0 -0
  37. mcp_proxy_adapter/examples/__pycache__/security_test_client.cpython-312.pyc +0 -0
  38. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
  39. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
  40. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +39 -0
  41. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +25 -0
  42. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
  43. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
  44. mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
  45. mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
  46. mcp_proxy_adapter/examples/cert_config.json +9 -0
  47. mcp_proxy_adapter/examples/certs/admin.crt +32 -0
  48. mcp_proxy_adapter/examples/certs/admin.key +52 -0
  49. mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
  50. mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
  51. mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
  52. mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
  53. mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
  54. mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
  55. mcp_proxy_adapter/examples/certs/client.crt +32 -0
  56. mcp_proxy_adapter/examples/certs/client.key +52 -0
  57. mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
  58. mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
  59. mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
  60. mcp_proxy_adapter/examples/certs/client_user.key +52 -0
  61. mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
  62. mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
  63. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
  64. mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
  65. mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
  66. mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
  67. mcp_proxy_adapter/examples/certs/readonly.key +52 -0
  68. mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
  69. mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
  70. mcp_proxy_adapter/examples/certs/server.crt +32 -0
  71. mcp_proxy_adapter/examples/certs/server.key +52 -0
  72. mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
  73. mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
  74. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
  75. mcp_proxy_adapter/examples/certs/user.crt +32 -0
  76. mcp_proxy_adapter/examples/certs/user.key +52 -0
  77. mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
  78. mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
  79. mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
  80. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
  81. mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
  82. mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
  83. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
  84. mcp_proxy_adapter/examples/commands/__init__.py +1 -0
  85. mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
  86. mcp_proxy_adapter/examples/debug_request_state.py +144 -0
  87. mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
  88. mcp_proxy_adapter/examples/demo_client.py +341 -0
  89. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
  90. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
  91. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
  92. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
  93. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
  94. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
  95. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
  96. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
  99. mcp_proxy_adapter/examples/full_application/main.py +138 -0
  100. mcp_proxy_adapter/examples/full_application/roles.json +21 -0
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
  102. mcp_proxy_adapter/examples/generate_certificates.py +121 -0
  103. mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
  104. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
  105. mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
  106. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
  107. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
  108. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
  109. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
  110. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
  111. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
  112. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
  124. mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
  125. mcp_proxy_adapter/examples/roles.json +38 -0
  126. mcp_proxy_adapter/examples/run_example.py +81 -0
  127. mcp_proxy_adapter/examples/run_security_tests.py +326 -0
  128. mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
  129. mcp_proxy_adapter/examples/security_test_client.py +743 -0
  130. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
  131. mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
  132. mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
  133. mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
  134. mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
  135. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
  136. mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
  137. mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
  138. mcp_proxy_adapter/examples/test_examples.py +344 -0
  139. mcp_proxy_adapter/examples/universal_client.py +628 -0
  140. mcp_proxy_adapter/main.py +21 -10
  141. mcp_proxy_adapter/utils/config_generator.py +639 -0
  142. mcp_proxy_adapter/version.py +2 -1
  143. mcp_proxy_adapter-6.1.0.dist-info/METADATA +205 -0
  144. mcp_proxy_adapter-6.1.0.dist-info/RECORD +193 -0
  145. mcp_proxy_adapter-6.1.0.dist-info/entry_points.txt +2 -0
  146. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/licenses/LICENSE +2 -2
  147. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  148. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  149. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  150. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  151. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  152. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  153. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  154. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  155. mcp_proxy_adapter/api/middleware/security.py +0 -376
  156. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  157. mcp_proxy_adapter/examples/__init__.py +0 -7
  158. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  159. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  160. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  161. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  162. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  163. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  164. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  165. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  166. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  167. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  168. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  169. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  170. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  171. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  172. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  173. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  174. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  175. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  176. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  177. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  178. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  179. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  180. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  181. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  182. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  183. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  184. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  185. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  186. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  187. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  188. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  189. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  190. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  191. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  192. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  193. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  194. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  195. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  196. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  197. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  198. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  199. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  200. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  201. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  202. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  203. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  204. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  205. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  206. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  207. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  208. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  209. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  210. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  211. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  212. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  213. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  214. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  215. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  216. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  217. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  218. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  219. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  220. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  221. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  222. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  223. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  224. mcp_proxy_adapter/tests/__init__.py +0 -0
  225. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  226. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  227. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  228. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  229. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  230. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  231. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  232. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  233. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  234. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  235. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  236. mcp_proxy_adapter/tests/conftest.py +0 -131
  237. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  238. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  239. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  240. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  241. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  242. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  243. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  244. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  245. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  246. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  247. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  248. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  249. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  250. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  251. mcp_proxy_adapter/tests/test_config.py +0 -127
  252. mcp_proxy_adapter/tests/test_utils.py +0 -65
  253. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  254. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  255. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  256. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  257. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  258. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/WHEEL +0 -0
  259. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,341 @@
1
+ """
2
+ Demo Client Script
3
+
4
+ This script demonstrates how to use the UniversalClient with different
5
+ authentication methods and connection types.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import asyncio
12
+ import json
13
+ import sys
14
+ from pathlib import Path
15
+
16
+ # Add project root to path
17
+ sys.path.insert(0, str(Path(__file__).parent.parent))
18
+
19
+ from examples.universal_client import UniversalClient, create_client_config
20
+
21
+
22
+ async def demo_from_config_file(config_file: str):
23
+ """
24
+ Demo client using configuration from file.
25
+
26
+ Args:
27
+ config_file: Path to configuration file
28
+ """
29
+ print(f"🚀 Demo from config file: {config_file}")
30
+ print("=" * 50)
31
+
32
+ try:
33
+ # Load configuration
34
+ with open(config_file, 'r') as f:
35
+ config = json.load(f)
36
+
37
+ print(f"Configuration loaded: {config.get('security', {}).get('auth_method', 'none')} auth")
38
+
39
+ # Create and use client
40
+ async with UniversalClient(config) as client:
41
+ # Test connection
42
+ success = await client.test_connection()
43
+
44
+ if success:
45
+ print("✅ Connection successful!")
46
+
47
+ # Test security features
48
+ security_results = await client.test_security_features()
49
+ print("\nSecurity Features:")
50
+ for feature, status in security_results.items():
51
+ status_icon = "✅" if status else "❌"
52
+ print(f" {status_icon} {feature}: {status}")
53
+
54
+ # Make API calls
55
+ await demo_api_calls(client)
56
+ else:
57
+ print("❌ Connection failed")
58
+
59
+ except FileNotFoundError:
60
+ print(f"❌ Configuration file not found: {config_file}")
61
+ except json.JSONDecodeError:
62
+ print(f"❌ Invalid JSON in configuration file: {config_file}")
63
+ except Exception as e:
64
+ print(f"❌ Demo failed: {e}")
65
+
66
+
67
+ async def demo_api_calls(client: UniversalClient):
68
+ """Demonstrate various API calls."""
69
+ print("\n📡 API Calls Demo:")
70
+ print("-" * 30)
71
+
72
+ # Test health endpoint
73
+ try:
74
+ health = await client.get("/health")
75
+ print(f"Health: {health}")
76
+ except Exception as e:
77
+ print(f"Health check failed: {e}")
78
+
79
+ # Test status endpoint
80
+ try:
81
+ status = await client.get("/api/status")
82
+ print(f"Status: {status}")
83
+ except Exception as e:
84
+ print(f"Status check failed: {e}")
85
+
86
+ # Test JSON-RPC command
87
+ try:
88
+ command_data = {
89
+ "jsonrpc": "2.0",
90
+ "method": "test_command",
91
+ "params": {
92
+ "message": "Hello from universal client!",
93
+ "timestamp": "2024-01-01T00:00:00Z"
94
+ },
95
+ "id": 1
96
+ }
97
+
98
+ result = await client.post("/api/jsonrpc", command_data)
99
+ print(f"Command Result: {result}")
100
+ except Exception as e:
101
+ print(f"Command execution failed: {e}")
102
+
103
+ # Test security command if available
104
+ try:
105
+ security_data = {
106
+ "jsonrpc": "2.0",
107
+ "method": "security_command",
108
+ "params": {
109
+ "action": "get_status",
110
+ "include_certificates": True
111
+ },
112
+ "id": 2
113
+ }
114
+
115
+ result = await client.post("/api/jsonrpc", security_data)
116
+ print(f"Security Status: {result}")
117
+ except Exception as e:
118
+ print(f"Security command failed: {e}")
119
+
120
+
121
+ async def demo_all_configs():
122
+ """Demo all available client configurations."""
123
+ print("🚀 Demo All Client Configurations")
124
+ print("=" * 50)
125
+
126
+ config_dir = Path(__file__).parent / "client_configs"
127
+
128
+ if not config_dir.exists():
129
+ print(f"❌ Config directory not found: {config_dir}")
130
+ return
131
+
132
+ config_files = list(config_dir.glob("*.json"))
133
+
134
+ if not config_files:
135
+ print(f"❌ No configuration files found in {config_dir}")
136
+ return
137
+
138
+ print(f"Found {len(config_files)} configuration files:")
139
+ for config_file in config_files:
140
+ print(f" - {config_file.name}")
141
+
142
+ print("\n" + "=" * 50)
143
+
144
+ for config_file in config_files:
145
+ await demo_from_config_file(str(config_file))
146
+ print("\n" + "-" * 50)
147
+
148
+
149
+ async def demo_programmatic_config():
150
+ """Demo client with programmatically created configuration."""
151
+ print("🚀 Demo Programmatic Configuration")
152
+ print("=" * 50)
153
+
154
+ # Create different configurations programmatically
155
+ configs = [
156
+ {
157
+ "name": "API Key Client",
158
+ "config": create_client_config(
159
+ "http://localhost:8000",
160
+ "api_key",
161
+ api_key="demo_api_key_123"
162
+ )
163
+ },
164
+ {
165
+ "name": "JWT Client",
166
+ "config": create_client_config(
167
+ "http://localhost:8000",
168
+ "jwt",
169
+ username="demo_user",
170
+ password="demo_password",
171
+ secret="demo_jwt_secret"
172
+ )
173
+ },
174
+ {
175
+ "name": "Certificate Client",
176
+ "config": create_client_config(
177
+ "https://localhost:8443",
178
+ "certificate",
179
+ cert_file="./certs/client.crt",
180
+ key_file="./keys/client.key",
181
+ ca_cert_file="./certs/ca.crt"
182
+ )
183
+ },
184
+ {
185
+ "name": "Basic Auth Client",
186
+ "config": create_client_config(
187
+ "http://localhost:8000",
188
+ "basic",
189
+ username="demo_user",
190
+ password="demo_password"
191
+ )
192
+ }
193
+ ]
194
+
195
+ for config_info in configs:
196
+ print(f"\n📋 Testing: {config_info['name']}")
197
+ print("-" * 30)
198
+
199
+ try:
200
+ async with UniversalClient(config_info["config"]) as client:
201
+ success = await client.test_connection()
202
+
203
+ if success:
204
+ print("✅ Connection successful!")
205
+ await demo_api_calls(client)
206
+ else:
207
+ print("❌ Connection failed")
208
+
209
+ except Exception as e:
210
+ print(f"❌ Test failed: {e}")
211
+
212
+
213
+ async def interactive_demo():
214
+ """Interactive demo with user input."""
215
+ print("🚀 Interactive Client Demo")
216
+ print("=" * 50)
217
+
218
+ print("Available authentication methods:")
219
+ print("1. No authentication")
220
+ print("2. API Key")
221
+ print("3. JWT Token")
222
+ print("4. Certificate")
223
+ print("5. Basic Authentication")
224
+
225
+ try:
226
+ choice = input("\nSelect authentication method (1-5): ").strip()
227
+
228
+ auth_methods = {
229
+ "1": "none",
230
+ "2": "api_key",
231
+ "3": "jwt",
232
+ "4": "certificate",
233
+ "5": "basic"
234
+ }
235
+
236
+ if choice not in auth_methods:
237
+ print("❌ Invalid choice")
238
+ return
239
+
240
+ auth_method = auth_methods[choice]
241
+
242
+ # Get server URL
243
+ server_url = input("Enter server URL (default: http://localhost:8000): ").strip()
244
+ if not server_url:
245
+ server_url = "http://localhost:8000"
246
+
247
+ # Create configuration based on choice
248
+ config_kwargs = {}
249
+
250
+ if auth_method == "api_key":
251
+ api_key = input("Enter API key: ").strip()
252
+ if api_key:
253
+ config_kwargs["api_key"] = api_key
254
+
255
+ elif auth_method == "jwt":
256
+ username = input("Enter username: ").strip()
257
+ password = input("Enter password: ").strip()
258
+ secret = input("Enter JWT secret: ").strip()
259
+ if username and password and secret:
260
+ config_kwargs.update({
261
+ "username": username,
262
+ "password": password,
263
+ "secret": secret
264
+ })
265
+
266
+ elif auth_method == "certificate":
267
+ cert_file = input("Enter certificate file path: ").strip()
268
+ key_file = input("Enter key file path: ").strip()
269
+ ca_cert_file = input("Enter CA certificate file path: ").strip()
270
+ if cert_file and key_file:
271
+ config_kwargs.update({
272
+ "cert_file": cert_file,
273
+ "key_file": key_file,
274
+ "ca_cert_file": ca_cert_file
275
+ })
276
+
277
+ elif auth_method == "basic":
278
+ username = input("Enter username: ").strip()
279
+ password = input("Enter password: ").strip()
280
+ if username and password:
281
+ config_kwargs.update({
282
+ "username": username,
283
+ "password": password
284
+ })
285
+
286
+ # Create configuration
287
+ config = create_client_config(server_url, auth_method, **config_kwargs)
288
+
289
+ print(f"\nConfiguration created for {auth_method} authentication")
290
+ print(f"Server URL: {server_url}")
291
+
292
+ # Test connection
293
+ async with UniversalClient(config) as client:
294
+ success = await client.test_connection()
295
+
296
+ if success:
297
+ print("✅ Connection successful!")
298
+ await demo_api_calls(client)
299
+ else:
300
+ print("❌ Connection failed")
301
+
302
+ except KeyboardInterrupt:
303
+ print("\n\nDemo interrupted by user")
304
+ except Exception as e:
305
+ print(f"❌ Interactive demo failed: {e}")
306
+
307
+
308
+ def main():
309
+ """Main demo function."""
310
+ if len(sys.argv) > 1:
311
+ command = sys.argv[1]
312
+
313
+ if command == "config":
314
+ if len(sys.argv) > 2:
315
+ config_file = sys.argv[2]
316
+ asyncio.run(demo_from_config_file(config_file))
317
+ else:
318
+ print("Usage: python demo_client.py config <config_file>")
319
+
320
+ elif command == "all":
321
+ asyncio.run(demo_all_configs())
322
+
323
+ elif command == "programmatic":
324
+ asyncio.run(demo_programmatic_config())
325
+
326
+ elif command == "interactive":
327
+ asyncio.run(interactive_demo())
328
+
329
+ else:
330
+ print("Unknown command. Available commands:")
331
+ print(" config <file> - Demo with config file")
332
+ print(" all - Demo all config files")
333
+ print(" programmatic - Demo programmatic configs")
334
+ print(" interactive - Interactive demo")
335
+ else:
336
+ # Default: demo all configs
337
+ asyncio.run(demo_all_configs())
338
+
339
+
340
+ if __name__ == "__main__":
341
+ main()
@@ -0,0 +1,99 @@
1
+ """
2
+ Custom Echo Command
3
+
4
+ This module demonstrates a custom command implementation for the full application example.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ from typing import Dict, Any, Optional
11
+ from mcp_proxy_adapter.commands.base import BaseCommand
12
+ from mcp_proxy_adapter.commands.result import CommandResult
13
+
14
+
15
+ class CustomEchoResult(CommandResult):
16
+ """Result class for custom echo command."""
17
+
18
+ def __init__(self, message: str, timestamp: str, echo_count: int):
19
+ self.message = message
20
+ self.timestamp = timestamp
21
+ self.echo_count = echo_count
22
+
23
+ def to_dict(self) -> Dict[str, Any]:
24
+ """Convert result to dictionary."""
25
+ return {
26
+ "message": self.message,
27
+ "timestamp": self.timestamp,
28
+ "echo_count": self.echo_count,
29
+ "command_type": "custom_echo"
30
+ }
31
+
32
+ def get_schema(self) -> Dict[str, Any]:
33
+ """Get result schema."""
34
+ return {
35
+ "type": "object",
36
+ "properties": {
37
+ "message": {"type": "string", "description": "Echoed message"},
38
+ "timestamp": {"type": "string", "description": "Timestamp of echo"},
39
+ "echo_count": {"type": "integer", "description": "Number of echoes"},
40
+ "command_type": {"type": "string", "description": "Command type"}
41
+ },
42
+ "required": ["message", "timestamp", "echo_count", "command_type"]
43
+ }
44
+
45
+
46
+ class CustomEchoCommand(BaseCommand):
47
+ """Custom echo command implementation."""
48
+
49
+ def __init__(self):
50
+ super().__init__()
51
+ self.echo_count = 0
52
+
53
+ def get_name(self) -> str:
54
+ """Get command name."""
55
+ return "custom_echo"
56
+
57
+ def get_description(self) -> str:
58
+ """Get command description."""
59
+ return "Custom echo command with enhanced features"
60
+
61
+ def get_schema(self) -> Dict[str, Any]:
62
+ """Get command schema."""
63
+ return {
64
+ "type": "object",
65
+ "properties": {
66
+ "message": {
67
+ "type": "string",
68
+ "description": "Message to echo",
69
+ "default": "Hello from custom echo!"
70
+ },
71
+ "repeat": {
72
+ "type": "integer",
73
+ "description": "Number of times to repeat",
74
+ "default": 1,
75
+ "minimum": 1,
76
+ "maximum": 10
77
+ }
78
+ },
79
+ "required": ["message"]
80
+ }
81
+
82
+ async def execute(self, params: Dict[str, Any]) -> CustomEchoResult:
83
+ """Execute the custom echo command."""
84
+ message = params.get("message", "Hello from custom echo!")
85
+ repeat = min(max(params.get("repeat", 1), 1), 10)
86
+
87
+ self.echo_count += 1
88
+
89
+ from datetime import datetime
90
+ timestamp = datetime.now().isoformat()
91
+
92
+ # Repeat the message
93
+ echoed_message = " ".join([message] * repeat)
94
+
95
+ return CustomEchoResult(
96
+ message=echoed_message,
97
+ timestamp=timestamp,
98
+ echo_count=self.echo_count
99
+ )
@@ -0,0 +1,106 @@
1
+ """
2
+ Dynamic Calculator Command
3
+
4
+ This module demonstrates a dynamically loaded command implementation for the full application example.
5
+
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+
10
+ from typing import Dict, Any, Optional
11
+ from mcp_proxy_adapter.commands.base import BaseCommand
12
+ from mcp_proxy_adapter.commands.result import CommandResult
13
+
14
+
15
+ class CalculatorResult(CommandResult):
16
+ """Result class for calculator command."""
17
+
18
+ def __init__(self, operation: str, result: float, expression: str):
19
+ self.operation = operation
20
+ self.result = result
21
+ self.expression = expression
22
+
23
+ def to_dict(self) -> Dict[str, Any]:
24
+ """Convert result to dictionary."""
25
+ return {
26
+ "operation": self.operation,
27
+ "result": self.result,
28
+ "expression": self.expression,
29
+ "command_type": "dynamic_calculator"
30
+ }
31
+
32
+ def get_schema(self) -> Dict[str, Any]:
33
+ """Get result schema."""
34
+ return {
35
+ "type": "object",
36
+ "properties": {
37
+ "operation": {"type": "string", "description": "Mathematical operation"},
38
+ "result": {"type": "number", "description": "Calculation result"},
39
+ "expression": {"type": "string", "description": "Full expression"},
40
+ "command_type": {"type": "string", "description": "Command type"}
41
+ },
42
+ "required": ["operation", "result", "expression", "command_type"]
43
+ }
44
+
45
+
46
+ class DynamicCalculatorCommand(BaseCommand):
47
+ """Dynamic calculator command implementation."""
48
+
49
+ def get_name(self) -> str:
50
+ """Get command name."""
51
+ return "dynamic_calculator"
52
+
53
+ def get_description(self) -> str:
54
+ """Get command description."""
55
+ return "Dynamic calculator with basic mathematical operations"
56
+
57
+ def get_schema(self) -> Dict[str, Any]:
58
+ """Get command schema."""
59
+ return {
60
+ "type": "object",
61
+ "properties": {
62
+ "operation": {
63
+ "type": "string",
64
+ "description": "Mathematical operation (add, subtract, multiply, divide)",
65
+ "enum": ["add", "subtract", "multiply", "divide"]
66
+ },
67
+ "a": {
68
+ "type": "number",
69
+ "description": "First number"
70
+ },
71
+ "b": {
72
+ "type": "number",
73
+ "description": "Second number"
74
+ }
75
+ },
76
+ "required": ["operation", "a", "b"]
77
+ }
78
+
79
+ async def execute(self, params: Dict[str, Any]) -> CalculatorResult:
80
+ """Execute the calculator command."""
81
+ operation = params.get("operation")
82
+ a = params.get("a")
83
+ b = params.get("b")
84
+
85
+ if operation == "add":
86
+ result = a + b
87
+ expression = f"{a} + {b}"
88
+ elif operation == "subtract":
89
+ result = a - b
90
+ expression = f"{a} - {b}"
91
+ elif operation == "multiply":
92
+ result = a * b
93
+ expression = f"{a} * {b}"
94
+ elif operation == "divide":
95
+ if b == 0:
96
+ raise ValueError("Division by zero is not allowed")
97
+ result = a / b
98
+ expression = f"{a} / {b}"
99
+ else:
100
+ raise ValueError(f"Unknown operation: {operation}")
101
+
102
+ return CalculatorResult(
103
+ operation=operation,
104
+ result=result,
105
+ expression=expression
106
+ )
@@ -0,0 +1,37 @@
1
+ {
2
+ "server": {
3
+ "host": "0.0.0.0",
4
+ "port": 8001,
5
+ "debug": false,
6
+ "log_level": "INFO"
7
+ },
8
+ "ssl": {
9
+ "enabled": false
10
+ },
11
+ "security": {
12
+ "enabled": true,
13
+ "auth": {
14
+ "enabled": true,
15
+ "methods": ["api_key"],
16
+ "api_keys": {
17
+ "admin": "admin-secret-key-123",
18
+ "user": "user-secret-key-456"
19
+ }
20
+ },
21
+ "rate_limit": {
22
+ "enabled": true,
23
+ "requests_per_minute": 60,
24
+ "requests_per_hour": 1000,
25
+ "burst_limit": 10
26
+ }
27
+ },
28
+ "logging": {
29
+ "level": "INFO",
30
+ "console_output": true,
31
+ "file_output": false
32
+ },
33
+ "commands": {
34
+ "auto_discovery": true,
35
+ "commands_directory": "./commands"
36
+ }
37
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "server": {
3
+ "host": "0.0.0.0",
4
+ "port": 8000,
5
+ "debug": false,
6
+ "log_level": "INFO"
7
+ },
8
+ "ssl": {
9
+ "enabled": false
10
+ },
11
+ "security": {
12
+ "enabled": false
13
+ },
14
+ "logging": {
15
+ "level": "INFO",
16
+ "console_output": true,
17
+ "file_output": false
18
+ },
19
+ "commands": {
20
+ "auto_discovery": true,
21
+ "commands_directory": "./commands"
22
+ }
23
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "server": {
3
+ "host": "0.0.0.0",
4
+ "port": 8444,
5
+ "debug": false,
6
+ "log_level": "INFO"
7
+ },
8
+ "ssl": {
9
+ "enabled": true,
10
+ "cert_file": "./certs/server.crt",
11
+ "key_file": "./certs/server.key"
12
+ },
13
+ "security": {
14
+ "enabled": true,
15
+ "auth": {
16
+ "enabled": true,
17
+ "methods": ["api_key"],
18
+ "api_keys": {
19
+ "admin": "admin-secret-key-123",
20
+ "user": "user-secret-key-456"
21
+ }
22
+ },
23
+ "rate_limit": {
24
+ "enabled": true,
25
+ "requests_per_minute": 60,
26
+ "requests_per_hour": 1000,
27
+ "burst_limit": 10
28
+ }
29
+ },
30
+ "logging": {
31
+ "level": "INFO",
32
+ "console_output": true,
33
+ "file_output": false
34
+ },
35
+ "commands": {
36
+ "auto_discovery": true,
37
+ "commands_directory": "./commands"
38
+ }
39
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "server": {
3
+ "host": "0.0.0.0",
4
+ "port": 8443,
5
+ "debug": false,
6
+ "log_level": "INFO"
7
+ },
8
+ "ssl": {
9
+ "enabled": true,
10
+ "cert_file": "./certs/server.crt",
11
+ "key_file": "./certs/server.key"
12
+ },
13
+ "security": {
14
+ "enabled": false
15
+ },
16
+ "logging": {
17
+ "level": "INFO",
18
+ "console_output": true,
19
+ "file_output": false
20
+ },
21
+ "commands": {
22
+ "auto_discovery": true,
23
+ "commands_directory": "./commands"
24
+ }
25
+ }