mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.0.1__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 (212) hide show
  1. mcp_proxy_adapter/__main__.py +27 -7
  2. mcp_proxy_adapter/api/app.py +209 -79
  3. mcp_proxy_adapter/api/handlers.py +16 -5
  4. mcp_proxy_adapter/api/middleware/__init__.py +14 -9
  5. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  6. mcp_proxy_adapter/api/middleware/factory.py +36 -12
  7. mcp_proxy_adapter/api/middleware/protocol_middleware.py +84 -18
  8. mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
  9. mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
  10. mcp_proxy_adapter/commands/__init__.py +7 -1
  11. mcp_proxy_adapter/commands/base.py +7 -4
  12. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  13. mcp_proxy_adapter/commands/command_registry.py +8 -0
  14. mcp_proxy_adapter/commands/echo_command.py +81 -0
  15. mcp_proxy_adapter/commands/health_command.py +1 -1
  16. mcp_proxy_adapter/commands/help_command.py +21 -14
  17. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  18. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  19. mcp_proxy_adapter/commands/security_command.py +488 -0
  20. mcp_proxy_adapter/commands/ssl_setup_command.py +234 -351
  21. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  22. mcp_proxy_adapter/config.py +323 -40
  23. mcp_proxy_adapter/core/app_factory.py +410 -0
  24. mcp_proxy_adapter/core/app_runner.py +272 -0
  25. mcp_proxy_adapter/core/certificate_utils.py +291 -73
  26. mcp_proxy_adapter/core/client.py +574 -0
  27. mcp_proxy_adapter/core/client_manager.py +284 -0
  28. mcp_proxy_adapter/core/client_security.py +384 -0
  29. mcp_proxy_adapter/core/logging.py +8 -3
  30. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  31. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  32. mcp_proxy_adapter/core/protocol_manager.py +169 -10
  33. mcp_proxy_adapter/core/proxy_client.py +602 -0
  34. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  35. mcp_proxy_adapter/core/security_adapter.py +12 -15
  36. mcp_proxy_adapter/core/security_integration.py +286 -0
  37. mcp_proxy_adapter/core/server_adapter.py +282 -0
  38. mcp_proxy_adapter/core/server_engine.py +270 -0
  39. mcp_proxy_adapter/core/ssl_utils.py +13 -12
  40. mcp_proxy_adapter/core/transport_manager.py +5 -5
  41. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  42. mcp_proxy_adapter/examples/__init__.py +13 -4
  43. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  44. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  45. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  46. mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
  47. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  48. mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
  49. mcp_proxy_adapter/examples/debug_request_state.py +112 -0
  50. mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
  51. mcp_proxy_adapter/examples/demo_client.py +275 -0
  52. mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
  53. mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
  54. mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
  55. mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
  56. mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
  57. mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
  58. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
  59. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  60. mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
  61. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
  62. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  63. mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
  64. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
  65. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  66. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  67. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
  68. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  69. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  70. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
  71. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  72. mcp_proxy_adapter/examples/full_application/main.py +173 -0
  73. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  74. mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
  75. mcp_proxy_adapter/examples/generate_certificates.py +177 -0
  76. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  77. mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
  78. mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
  79. mcp_proxy_adapter/examples/run_example.py +59 -0
  80. mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
  81. mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
  82. mcp_proxy_adapter/examples/run_security_tests.py +544 -0
  83. mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
  84. mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
  85. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
  86. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
  87. mcp_proxy_adapter/examples/security_test_client.py +782 -0
  88. mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
  89. mcp_proxy_adapter/examples/test_config.py +148 -0
  90. mcp_proxy_adapter/examples/test_config_generator.py +86 -0
  91. mcp_proxy_adapter/examples/test_examples.py +281 -0
  92. mcp_proxy_adapter/examples/universal_client.py +620 -0
  93. mcp_proxy_adapter/main.py +66 -148
  94. mcp_proxy_adapter/utils/config_generator.py +1008 -0
  95. mcp_proxy_adapter/version.py +5 -2
  96. mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
  97. mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
  98. mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
  99. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
  100. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  101. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  102. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  103. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  104. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  105. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  106. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  107. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  108. mcp_proxy_adapter/api/middleware/security.py +0 -376
  109. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  110. mcp_proxy_adapter/examples/README.md +0 -124
  111. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  112. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  113. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  114. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  115. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  116. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  117. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  118. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  119. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  120. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  121. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  122. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  123. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  124. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  125. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  126. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  127. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  128. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  129. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  130. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  131. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  132. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  133. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  134. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  135. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  136. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  137. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  138. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  139. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  140. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  141. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  142. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  143. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  144. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  145. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  146. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  147. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  148. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  149. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  150. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  151. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  152. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  153. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  154. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  155. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  156. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  157. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  158. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  159. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  160. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  161. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  162. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  163. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  164. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  165. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  166. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  167. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  168. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  169. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  170. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  171. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  172. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  173. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  174. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  175. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  176. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  177. mcp_proxy_adapter/tests/__init__.py +0 -0
  178. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  179. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  180. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  181. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  182. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  183. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  184. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  185. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  186. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  187. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  188. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  189. mcp_proxy_adapter/tests/conftest.py +0 -131
  190. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  191. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  192. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  193. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  194. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  195. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  196. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  197. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  198. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  199. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  200. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  201. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  202. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  203. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  204. mcp_proxy_adapter/tests/test_config.py +0 -127
  205. mcp_proxy_adapter/tests/test_utils.py +0 -65
  206. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  207. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  208. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  209. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  210. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  211. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
  212. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Debug Role Chain - Анализ цепочки блокировки ролей
4
+ Этот скрипт анализирует всю цепочку от аутентификации до блокировки доступа.
5
+ Author: Vasiliy Zdanovskiy
6
+ email: vasilyvz@gmail.com
7
+ """
8
+ import asyncio
9
+ import json
10
+ import sys
11
+ from pathlib import Path
12
+ # Add project root to path
13
+ project_root = Path(__file__).parent.parent.parent
14
+ sys.path.insert(0, str(project_root))
15
+ from mcp_security_framework import SecurityManager, AuthManager, PermissionManager
16
+ from mcp_security_framework.schemas.config import SecurityConfig, AuthConfig, PermissionConfig
17
+ async def debug_role_chain():
18
+ """Debug the complete role chain from authentication to blocking."""
19
+ print("🔍 АНАЛИЗ ЦЕПОЧКИ БЛОКИРОВКИ РОЛЕЙ")
20
+ print("=" * 60)
21
+ # Load configuration
22
+ config_path = project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "config_http_token.json"
23
+ with open(config_path) as f:
24
+ config = json.load(f)
25
+ security_config = config.get("security", {})
26
+ print("📋 1. КОНФИГУРАЦИЯ API КЛЮЧЕЙ")
27
+ print("-" * 30)
28
+ api_keys = security_config.get("auth", {}).get("api_keys", {})
29
+ for key, value in api_keys.items():
30
+ print(f" {key}: {value}")
31
+ print("\n📋 2. КОНФИГУРАЦИЯ РОЛЕЙ")
32
+ print("-" * 30)
33
+ roles_config = security_config.get("permissions", {}).get("roles", {})
34
+ for role, permissions in roles_config.items():
35
+ print(f" {role}: {permissions}")
36
+ print("\n📋 3. СОЗДАНИЕ КОМПОНЕНТОВ БЕЗОПАСНОСТИ")
37
+ print("-" * 30)
38
+ # Create permission config
39
+ perm_config = PermissionConfig(
40
+ roles_file=str(project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "roles.json"),
41
+ default_role="guest",
42
+ admin_role="admin",
43
+ role_hierarchy=security_config.get("permissions", {}).get("role_hierarchy", {}),
44
+ permission_cache_enabled=True,
45
+ permission_cache_ttl=300,
46
+ wildcard_permissions=False,
47
+ strict_mode=True,
48
+ roles=roles_config
49
+ )
50
+ # Create auth config
51
+ auth_config = AuthConfig(
52
+ enabled=security_config.get("auth", {}).get("enabled", True),
53
+ methods=security_config.get("auth", {}).get("methods", ["api_key"]),
54
+ api_keys=api_keys,
55
+ user_roles=security_config.get("auth", {}).get("user_roles", {}),
56
+ jwt_secret=security_config.get("auth", {}).get("jwt_secret"),
57
+ jwt_algorithm=security_config.get("auth", {}).get("jwt_algorithm", "HS256"),
58
+ jwt_expiry_hours=security_config.get("auth", {}).get("jwt_expiry_hours", 24),
59
+ certificate_auth=security_config.get("auth", {}).get("certificate_auth", False),
60
+ certificate_roles_oid=security_config.get("auth", {}).get("certificate_roles_oid"),
61
+ certificate_permissions_oid=security_config.get("auth", {}).get("certificate_permissions_oid"),
62
+ basic_auth=security_config.get("auth", {}).get("basic_auth", False),
63
+ oauth2_config=security_config.get("auth", {}).get("oauth2_config"),
64
+ public_paths=security_config.get("auth", {}).get("public_paths", [])
65
+ )
66
+ # Create security config
67
+ security_config_obj = SecurityConfig(
68
+ auth=auth_config,
69
+ permissions=perm_config
70
+ )
71
+ print("✅ Конфигурации созданы")
72
+ print("\n📋 4. ИНИЦИАЛИЗАЦИЯ МЕНЕДЖЕРОВ")
73
+ print("-" * 30)
74
+ # Initialize managers
75
+ permission_manager = PermissionManager(perm_config)
76
+ auth_manager = AuthManager(auth_config, permission_manager)
77
+ security_manager = SecurityManager(security_config_obj)
78
+ print("✅ Менеджеры инициализированы")
79
+ print("\n📋 5. ТЕСТИРОВАНИЕ АУТЕНТИФИКАЦИИ")
80
+ print("-" * 30)
81
+ # Test authentication with different tokens
82
+ test_tokens = {
83
+ "admin": "test-token-123",
84
+ "user": "user-token-456",
85
+ "readonly": "readonly-token-123",
86
+ "invalid": "invalid-token-999"
87
+ }
88
+ auth_results = {}
89
+ for role, token in test_tokens.items():
90
+ print(f"\n🔐 Тестирование токена для роли '{role}': {token}")
91
+ try:
92
+ result = auth_manager.authenticate_api_key(token)
93
+ auth_results[role] = result
94
+ print(f" ✅ Аутентификация: {'УСПЕШНА' if result.is_valid else 'НЕУДАЧНА'}")
95
+ if result.is_valid:
96
+ print(f" 👤 Пользователь: {result.username}")
97
+ print(f" 🏷️ Роли: {result.roles}")
98
+ print(f" 🔑 Метод: {result.auth_method}")
99
+ else:
100
+ print(f" ❌ Ошибка: {result.error_message}")
101
+ except Exception as e:
102
+ print(f" ❌ Исключение: {e}")
103
+ auth_results[role] = None
104
+ print("\n📋 6. ТЕСТИРОВАНИЕ ПРАВ ДОСТУПА")
105
+ print("-" * 30)
106
+ # Test permissions for different actions
107
+ test_actions = ["read", "write", "manage", "delete"]
108
+ for role, auth_result in auth_results.items():
109
+ if auth_result and auth_result.is_valid:
110
+ print(f"\n🔒 Тестирование прав для роли '{role}' (роли: {auth_result.roles})")
111
+ for action in test_actions:
112
+ try:
113
+ # Check permissions using permission manager
114
+ validation_result = permission_manager.validate_access(
115
+ auth_result.roles,
116
+ [action]
117
+ )
118
+ status = "✅ РАЗРЕШЕНО" if validation_result.is_valid else "❌ ЗАБЛОКИРОВАНО"
119
+ print(f" {action}: {status}")
120
+ if not validation_result.is_valid:
121
+ print(f" 📝 Причина: {validation_result.error_message}")
122
+ print(f" 🎯 Эффективные права: {validation_result.effective_permissions}")
123
+ print(f" ❌ Отсутствующие права: {validation_result.missing_permissions}")
124
+ except Exception as e:
125
+ print(f" {action}: ❌ ОШИБКА - {e}")
126
+ print("\n📋 7. ТЕСТИРОВАНИЕ ПОЛНОЙ ЦЕПОЧКИ")
127
+ print("-" * 30)
128
+ # Test complete request validation
129
+ for role, token in test_tokens.items():
130
+ print(f"\n🔄 Полная цепочка для роли '{role}'")
131
+ request_data = {
132
+ "api_key": token,
133
+ "required_permissions": ["write"],
134
+ "client_ip": "127.0.0.1"
135
+ }
136
+ try:
137
+ result = security_manager.validate_request(request_data)
138
+ status = "✅ УСПЕШНО" if result.is_valid else "❌ ЗАБЛОКИРОВАНО"
139
+ print(f" Результат: {status}")
140
+ if not result.is_valid:
141
+ print(f" 📝 Причина: {result.error_message}")
142
+ except Exception as e:
143
+ print(f" ❌ ОШИБКА: {e}")
144
+ print("\n📋 8. АНАЛИЗ ПРОБЛЕМЫ")
145
+ print("-" * 30)
146
+ print("🔍 ПРОБЛЕМА: Readonly роль получает доступ к write операциям")
147
+ print("\n📋 ВОЗМОЖНЫЕ ПРИЧИНЫ:")
148
+ print("1. Middleware не передает информацию о пользователе в request.state")
149
+ print("2. Framework middleware не блокирует доступ на уровне middleware")
150
+ print("3. Команда role_test не получает правильный контекст пользователя")
151
+ print("4. Интеграция между middleware и командами не работает")
152
+ print("\n📋 РЕКОМЕНДАЦИИ:")
153
+ print("1. Проверить, как framework middleware устанавливает user info")
154
+ print("2. Добавить проверку прав на уровне middleware")
155
+ print("3. Убедиться, что request.state содержит user info")
156
+ print("4. Проверить интеграцию между middleware и командами")
157
+ if __name__ == "__main__":
158
+ asyncio.run(debug_role_chain())
@@ -0,0 +1,275 @@
1
+ """
2
+ Demo Client Script
3
+ This script demonstrates how to use the UniversalClient with different
4
+ authentication methods and connection types.
5
+ Author: Vasiliy Zdanovskiy
6
+ email: vasilyvz@gmail.com
7
+ """
8
+ import asyncio
9
+ import json
10
+ import sys
11
+ from pathlib import Path
12
+ # Add project root to path
13
+ sys.path.insert(0, str(Path(__file__).parent.parent))
14
+ from examples.universal_client import UniversalClient, create_client_config
15
+ async def demo_from_config_file(config_file: str):
16
+ """
17
+ Demo client using configuration from file.
18
+ Args:
19
+ config_file: Path to configuration file
20
+ """
21
+ print(f"🚀 Demo from config file: {config_file}")
22
+ print("=" * 50)
23
+ try:
24
+ # Load configuration
25
+ with open(config_file, 'r') as f:
26
+ config = json.load(f)
27
+ print(f"Configuration loaded: {config.get('security', {}).get('auth_method', 'none')} auth")
28
+ # Create and use client
29
+ async with UniversalClient(config) as client:
30
+ # Test connection
31
+ success = await client.test_connection()
32
+ if success:
33
+ print("✅ Connection successful!")
34
+ # Test security features
35
+ security_results = await client.test_security_features()
36
+ print("\nSecurity Features:")
37
+ for feature, status in security_results.items():
38
+ status_icon = "✅" if status else "❌"
39
+ print(f" {status_icon} {feature}: {status}")
40
+ # Make API calls
41
+ await demo_api_calls(client)
42
+ else:
43
+ print("❌ Connection failed")
44
+ except FileNotFoundError:
45
+ print(f"❌ Configuration file not found: {config_file}")
46
+ except json.JSONDecodeError:
47
+ print(f"❌ Invalid JSON in configuration file: {config_file}")
48
+ except Exception as e:
49
+ print(f"❌ Demo failed: {e}")
50
+ async def demo_api_calls(client: UniversalClient):
51
+ """Demonstrate various API calls."""
52
+ print("\n📡 API Calls Demo:")
53
+ print("-" * 30)
54
+ # Test health endpoint
55
+ try:
56
+ health = await client.get("/health")
57
+ print(f"Health: {health}")
58
+ except Exception as e:
59
+ print(f"Health check failed: {e}")
60
+ # Test status endpoint
61
+ try:
62
+ status = await client.get("/api/status")
63
+ print(f"Status: {status}")
64
+ except Exception as e:
65
+ print(f"Status check failed: {e}")
66
+ # Test JSON-RPC command
67
+ try:
68
+ command_data = {
69
+ "jsonrpc": "2.0",
70
+ "method": "test_command",
71
+ "params": {
72
+ "message": "Hello from universal client!",
73
+ "timestamp": "2024-01-01T00:00:00Z"
74
+ },
75
+ "id": 1
76
+ }
77
+ result = await client.post("/api/jsonrpc", command_data)
78
+ print(f"Command Result: {result}")
79
+ except Exception as e:
80
+ print(f"Command execution failed: {e}")
81
+ # Test security command if available
82
+ try:
83
+ security_data = {
84
+ "jsonrpc": "2.0",
85
+ "method": "security_command",
86
+ "params": {
87
+ "action": "get_status",
88
+ "include_certificates": True
89
+ },
90
+ "id": 2
91
+ }
92
+ result = await client.post("/api/jsonrpc", security_data)
93
+ print(f"Security Status: {result}")
94
+ except Exception as e:
95
+ print(f"Security command failed: {e}")
96
+ async def demo_all_configs():
97
+ """Demo all available client configurations."""
98
+ print("🚀 Demo All Client Configurations")
99
+ print("=" * 50)
100
+ config_dir = Path(__file__).parent / "client_configs"
101
+ if not config_dir.exists():
102
+ print(f"❌ Config directory not found: {config_dir}")
103
+ return
104
+ config_files = list(config_dir.glob("*.json"))
105
+ if not config_files:
106
+ print(f"❌ No configuration files found in {config_dir}")
107
+ return
108
+ print(f"Found {len(config_files)} configuration files:")
109
+ for config_file in config_files:
110
+ print(f" - {config_file.name}")
111
+ print("\n" + "=" * 50)
112
+ for config_file in config_files:
113
+ await demo_from_config_file(str(config_file))
114
+ print("\n" + "-" * 50)
115
+ async def demo_programmatic_config():
116
+ """Demo client with programmatically created configuration."""
117
+ print("🚀 Demo Programmatic Configuration")
118
+ print("=" * 50)
119
+ # Create different configurations programmatically
120
+ configs = [
121
+ {
122
+ "name": "API Key Client",
123
+ "config": create_client_config(
124
+ "http://localhost:8000",
125
+ "api_key",
126
+ api_key="demo_api_key_123"
127
+ )
128
+ },
129
+ {
130
+ "name": "JWT Client",
131
+ "config": create_client_config(
132
+ "http://localhost:8000",
133
+ "jwt",
134
+ username="demo_user",
135
+ password="demo_password",
136
+ secret="demo_jwt_secret"
137
+ )
138
+ },
139
+ {
140
+ "name": "Certificate Client",
141
+ "config": create_client_config(
142
+ "https://localhost:8443",
143
+ "certificate",
144
+ cert_file="./certs/client.crt",
145
+ key_file="./keys/client.key",
146
+ ca_cert_file="./certs/ca.crt"
147
+ )
148
+ },
149
+ {
150
+ "name": "Basic Auth Client",
151
+ "config": create_client_config(
152
+ "http://localhost:8000",
153
+ "basic",
154
+ username="demo_user",
155
+ password="demo_password"
156
+ )
157
+ }
158
+ ]
159
+ for config_info in configs:
160
+ print(f"\n📋 Testing: {config_info['name']}")
161
+ print("-" * 30)
162
+ try:
163
+ async with UniversalClient(config_info["config"]) as client:
164
+ success = await client.test_connection()
165
+ if success:
166
+ print("✅ Connection successful!")
167
+ await demo_api_calls(client)
168
+ else:
169
+ print("❌ Connection failed")
170
+ except Exception as e:
171
+ print(f"❌ Test failed: {e}")
172
+ async def interactive_demo():
173
+ """Interactive demo with user input."""
174
+ print("🚀 Interactive Client Demo")
175
+ print("=" * 50)
176
+ print("Available authentication methods:")
177
+ print("1. No authentication")
178
+ print("2. API Key")
179
+ print("3. JWT Token")
180
+ print("4. Certificate")
181
+ print("5. Basic Authentication")
182
+ try:
183
+ choice = input("\nSelect authentication method (1-5): ").strip()
184
+ auth_methods = {
185
+ "1": "none",
186
+ "2": "api_key",
187
+ "3": "jwt",
188
+ "4": "certificate",
189
+ "5": "basic"
190
+ }
191
+ if choice not in auth_methods:
192
+ print("❌ Invalid choice")
193
+ return
194
+ auth_method = auth_methods[choice]
195
+ # Get server URL
196
+ server_url = input("Enter server URL (default: http://localhost:8000): ").strip()
197
+ if not server_url:
198
+ server_url = "http://localhost:8000"
199
+ # Create configuration based on choice
200
+ config_kwargs = {}
201
+ if auth_method == "api_key":
202
+ api_key = input("Enter API key: ").strip()
203
+ if api_key:
204
+ config_kwargs["api_key"] = api_key
205
+ elif auth_method == "jwt":
206
+ username = input("Enter username: ").strip()
207
+ password = input("Enter password: ").strip()
208
+ secret = input("Enter JWT secret: ").strip()
209
+ if username and password and secret:
210
+ config_kwargs.update({
211
+ "username": username,
212
+ "password": password,
213
+ "secret": secret
214
+ })
215
+ elif auth_method == "certificate":
216
+ cert_file = input("Enter certificate file path: ").strip()
217
+ key_file = input("Enter key file path: ").strip()
218
+ ca_cert_file = input("Enter CA certificate file path: ").strip()
219
+ if cert_file and key_file:
220
+ config_kwargs.update({
221
+ "cert_file": cert_file,
222
+ "key_file": key_file,
223
+ "ca_cert_file": ca_cert_file
224
+ })
225
+ elif auth_method == "basic":
226
+ username = input("Enter username: ").strip()
227
+ password = input("Enter password: ").strip()
228
+ if username and password:
229
+ config_kwargs.update({
230
+ "username": username,
231
+ "password": password
232
+ })
233
+ # Create configuration
234
+ config = create_client_config(server_url, auth_method, **config_kwargs)
235
+ print(f"\nConfiguration created for {auth_method} authentication")
236
+ print(f"Server URL: {server_url}")
237
+ # Test connection
238
+ async with UniversalClient(config) as client:
239
+ success = await client.test_connection()
240
+ if success:
241
+ print("✅ Connection successful!")
242
+ await demo_api_calls(client)
243
+ else:
244
+ print("❌ Connection failed")
245
+ except KeyboardInterrupt:
246
+ print("\n\nDemo interrupted by user")
247
+ except Exception as e:
248
+ print(f"❌ Interactive demo failed: {e}")
249
+ def main():
250
+ """Main demo function."""
251
+ if len(sys.argv) > 1:
252
+ command = sys.argv[1]
253
+ if command == "config":
254
+ if len(sys.argv) > 2:
255
+ config_file = sys.argv[2]
256
+ asyncio.run(demo_from_config_file(config_file))
257
+ else:
258
+ print("Usage: python demo_client.py config <config_file>")
259
+ elif command == "all":
260
+ asyncio.run(demo_all_configs())
261
+ elif command == "programmatic":
262
+ asyncio.run(demo_programmatic_config())
263
+ elif command == "interactive":
264
+ asyncio.run(interactive_demo())
265
+ else:
266
+ print("Unknown command. Available commands:")
267
+ print(" config <file> - Demo with config file")
268
+ print(" all - Demo all config files")
269
+ print(" programmatic - Demo programmatic configs")
270
+ print(" interactive - Interactive demo")
271
+ else:
272
+ # Default: demo all configs
273
+ asyncio.run(demo_all_configs())
274
+ if __name__ == "__main__":
275
+ main()
@@ -0,0 +1,9 @@
1
+ """Basic Framework Example.
2
+
3
+ This example demonstrates the fundamental usage of MCP Proxy Adapter
4
+ with minimal configuration and basic command registration.
5
+
6
+ Note: This package provides a basic example of MCP Proxy Adapter usage.
7
+ The main application is created dynamically in main.py and not exported
8
+ as a global variable for this example.
9
+ """
@@ -0,0 +1,4 @@
1
+ """Basic Framework Commands.
2
+
3
+ Commands for the basic framework example.
4
+ """
@@ -0,0 +1,4 @@
1
+ """Basic Framework Hooks.
2
+
3
+ Hooks for the basic framework example.
4
+ """
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Basic Framework Example
4
+ This example demonstrates the basic usage of the MCP Proxy Adapter framework
5
+ with minimal configuration and built-in commands.
6
+ Author: Vasiliy Zdanovskiy
7
+ email: vasilyvz@gmail.com
8
+ """
9
+ import sys
10
+ import argparse
11
+ from pathlib import Path
12
+ # Add the framework to the path
13
+ sys.path.insert(0, str(Path(__file__).parent.parent.parent))
14
+ from mcp_proxy_adapter.core.app_factory import create_and_run_server
15
+ def main():
16
+ """Main entry point for the basic framework example."""
17
+ parser = argparse.ArgumentParser(description="Basic Framework Example")
18
+ parser.add_argument("--config", "-c", required=True, help="Path to configuration file")
19
+ parser.add_argument("--host", help="Server host")
20
+ parser.add_argument("--port", type=int, help="Server port")
21
+ parser.add_argument("--debug", action="store_true", help="Enable debug mode")
22
+ args = parser.parse_args()
23
+ # Override configuration if specified
24
+ config_overrides = {}
25
+ if args.host:
26
+ config_overrides["host"] = args.host
27
+ if args.port:
28
+ config_overrides["port"] = args.port
29
+ if args.debug:
30
+ config_overrides["debug"] = True
31
+ print(f"🚀 Starting Basic Framework Example")
32
+ print(f"📋 Configuration: {args.config}")
33
+ print("=" * 50)
34
+ # Use the factory method to create and run the server
35
+ create_and_run_server(
36
+ config_path=args.config,
37
+ title="Basic Framework Example",
38
+ description="Basic MCP Proxy Adapter with minimal configuration",
39
+ version="1.0.0",
40
+ host=config_overrides.get("host", "0.0.0.0"),
41
+ log_level="debug" if config_overrides.get("debug", False) else "info"
42
+ )
43
+ if __name__ == "__main__":
44
+ main()
@@ -0,0 +1,12 @@
1
+ """Full Application Example.
2
+
3
+ This example demonstrates advanced usage of MCP Proxy Adapter including:
4
+ - Proxy registration endpoints
5
+ - Custom command hooks
6
+ - Advanced security configurations
7
+ - Role-based access control
8
+ """
9
+
10
+ from .main import get_app
11
+ app = get_app()
12
+ from .proxy_endpoints import router as proxy_router
@@ -0,0 +1,7 @@
1
+ """Full Application Commands.
2
+
3
+ Custom command implementations for the full application example.
4
+ """
5
+
6
+ from .custom_echo_command import CustomEchoCommand
7
+ from .dynamic_calculator_command import DynamicCalculatorCommand
@@ -0,0 +1,80 @@
1
+ """
2
+ Custom Echo Command
3
+ This module demonstrates a custom command implementation for the full application example.
4
+ Author: Vasiliy Zdanovskiy
5
+ email: vasilyvz@gmail.com
6
+ """
7
+ from typing import Dict, Any, Optional
8
+ from mcp_proxy_adapter.commands.base import BaseCommand
9
+ from mcp_proxy_adapter.commands.result import CommandResult
10
+ class CustomEchoResult(CommandResult):
11
+ """Result class for custom echo command."""
12
+ def __init__(self, message: str, timestamp: str, echo_count: int):
13
+ self.message = message
14
+ self.timestamp = timestamp
15
+ self.echo_count = echo_count
16
+ def to_dict(self) -> Dict[str, Any]:
17
+ """Convert result to dictionary."""
18
+ return {
19
+ "message": self.message,
20
+ "timestamp": self.timestamp,
21
+ "echo_count": self.echo_count,
22
+ "command_type": "custom_echo"
23
+ }
24
+ def get_schema(self) -> Dict[str, Any]:
25
+ """Get result schema."""
26
+ return {
27
+ "type": "object",
28
+ "properties": {
29
+ "message": {"type": "string", "description": "Echoed message"},
30
+ "timestamp": {"type": "string", "description": "Timestamp of echo"},
31
+ "echo_count": {"type": "integer", "description": "Number of echoes"},
32
+ "command_type": {"type": "string", "description": "Command type"}
33
+ },
34
+ "required": ["message", "timestamp", "echo_count", "command_type"]
35
+ }
36
+ class CustomEchoCommand(BaseCommand):
37
+ """Custom echo command implementation."""
38
+ def __init__(self):
39
+ super().__init__()
40
+ self.echo_count = 0
41
+ def get_name(self) -> str:
42
+ """Get command name."""
43
+ return "custom_echo"
44
+ def get_description(self) -> str:
45
+ """Get command description."""
46
+ return "Custom echo command with enhanced features"
47
+ def get_schema(self) -> Dict[str, Any]:
48
+ """Get command schema."""
49
+ return {
50
+ "type": "object",
51
+ "properties": {
52
+ "message": {
53
+ "type": "string",
54
+ "description": "Message to echo",
55
+ "default": "Hello from custom echo!"
56
+ },
57
+ "repeat": {
58
+ "type": "integer",
59
+ "description": "Number of times to repeat",
60
+ "default": 1,
61
+ "minimum": 1,
62
+ "maximum": 10
63
+ }
64
+ },
65
+ "required": ["message"]
66
+ }
67
+ async def execute(self, params: Dict[str, Any]) -> CustomEchoResult:
68
+ """Execute the custom echo command."""
69
+ message = params.get("message", "Hello from custom echo!")
70
+ repeat = min(max(params.get("repeat", 1), 1), 10)
71
+ self.echo_count += 1
72
+ from datetime import datetime
73
+ timestamp = datetime.now().isoformat()
74
+ # Repeat the message
75
+ echoed_message = " ".join([message] * repeat)
76
+ return CustomEchoResult(
77
+ message=echoed_message,
78
+ timestamp=timestamp,
79
+ echo_count=self.echo_count
80
+ )