mcp-proxy-adapter 4.1.1__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 (200) hide show
  1. mcp_proxy_adapter/__main__.py +32 -0
  2. mcp_proxy_adapter/api/app.py +290 -33
  3. mcp_proxy_adapter/api/handlers.py +32 -6
  4. mcp_proxy_adapter/api/middleware/__init__.py +38 -32
  5. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  6. mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
  7. mcp_proxy_adapter/api/middleware/factory.py +243 -0
  8. mcp_proxy_adapter/api/middleware/logging.py +32 -6
  9. mcp_proxy_adapter/api/middleware/protocol_middleware.py +201 -0
  10. mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
  11. mcp_proxy_adapter/api/middleware/unified_security.py +197 -0
  12. mcp_proxy_adapter/api/middleware/user_info_middleware.py +158 -0
  13. mcp_proxy_adapter/commands/__init__.py +19 -4
  14. mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
  15. mcp_proxy_adapter/commands/base.py +66 -32
  16. mcp_proxy_adapter/commands/builtin_commands.py +95 -0
  17. mcp_proxy_adapter/commands/catalog_manager.py +838 -0
  18. mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
  19. mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
  20. mcp_proxy_adapter/commands/command_registry.py +711 -354
  21. mcp_proxy_adapter/commands/dependency_manager.py +245 -0
  22. mcp_proxy_adapter/commands/echo_command.py +81 -0
  23. mcp_proxy_adapter/commands/health_command.py +8 -1
  24. mcp_proxy_adapter/commands/help_command.py +21 -14
  25. mcp_proxy_adapter/commands/hooks.py +200 -167
  26. mcp_proxy_adapter/commands/key_management_command.py +506 -0
  27. mcp_proxy_adapter/commands/load_command.py +176 -0
  28. mcp_proxy_adapter/commands/plugins_command.py +235 -0
  29. mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
  30. mcp_proxy_adapter/commands/proxy_registration_command.py +409 -0
  31. mcp_proxy_adapter/commands/reload_command.py +48 -50
  32. mcp_proxy_adapter/commands/result.py +1 -0
  33. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  34. mcp_proxy_adapter/commands/roles_management_command.py +697 -0
  35. mcp_proxy_adapter/commands/security_command.py +488 -0
  36. mcp_proxy_adapter/commands/ssl_setup_command.py +366 -0
  37. mcp_proxy_adapter/commands/token_management_command.py +529 -0
  38. mcp_proxy_adapter/commands/transport_management_command.py +144 -0
  39. mcp_proxy_adapter/commands/unload_command.py +158 -0
  40. mcp_proxy_adapter/config.py +394 -14
  41. mcp_proxy_adapter/core/app_factory.py +410 -0
  42. mcp_proxy_adapter/core/app_runner.py +272 -0
  43. mcp_proxy_adapter/core/auth_validator.py +606 -0
  44. mcp_proxy_adapter/core/certificate_utils.py +1045 -0
  45. mcp_proxy_adapter/core/client.py +574 -0
  46. mcp_proxy_adapter/core/client_manager.py +284 -0
  47. mcp_proxy_adapter/core/client_security.py +384 -0
  48. mcp_proxy_adapter/core/config_converter.py +405 -0
  49. mcp_proxy_adapter/core/config_validator.py +218 -0
  50. mcp_proxy_adapter/core/logging.py +19 -3
  51. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  52. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  53. mcp_proxy_adapter/core/protocol_manager.py +385 -0
  54. mcp_proxy_adapter/core/proxy_client.py +602 -0
  55. mcp_proxy_adapter/core/proxy_registration.py +522 -0
  56. mcp_proxy_adapter/core/role_utils.py +426 -0
  57. mcp_proxy_adapter/core/security_adapter.py +370 -0
  58. mcp_proxy_adapter/core/security_factory.py +239 -0
  59. mcp_proxy_adapter/core/security_integration.py +286 -0
  60. mcp_proxy_adapter/core/server_adapter.py +282 -0
  61. mcp_proxy_adapter/core/server_engine.py +270 -0
  62. mcp_proxy_adapter/core/settings.py +1 -0
  63. mcp_proxy_adapter/core/ssl_utils.py +234 -0
  64. mcp_proxy_adapter/core/transport_manager.py +292 -0
  65. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  66. mcp_proxy_adapter/custom_openapi.py +22 -11
  67. mcp_proxy_adapter/examples/__init__.py +13 -4
  68. mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
  69. mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
  70. mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
  71. mcp_proxy_adapter/examples/basic_framework/main.py +44 -0
  72. mcp_proxy_adapter/examples/commands/__init__.py +5 -0
  73. mcp_proxy_adapter/examples/create_certificates_simple.py +550 -0
  74. mcp_proxy_adapter/examples/debug_request_state.py +112 -0
  75. mcp_proxy_adapter/examples/debug_role_chain.py +158 -0
  76. mcp_proxy_adapter/examples/demo_client.py +275 -0
  77. mcp_proxy_adapter/examples/examples/basic_framework/__init__.py +9 -0
  78. mcp_proxy_adapter/examples/examples/basic_framework/commands/__init__.py +4 -0
  79. mcp_proxy_adapter/examples/examples/basic_framework/hooks/__init__.py +4 -0
  80. mcp_proxy_adapter/examples/examples/basic_framework/main.py +44 -0
  81. mcp_proxy_adapter/examples/examples/full_application/__init__.py +12 -0
  82. mcp_proxy_adapter/examples/examples/full_application/commands/__init__.py +7 -0
  83. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +80 -0
  84. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  85. mcp_proxy_adapter/examples/examples/full_application/hooks/__init__.py +7 -0
  86. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +75 -0
  87. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  88. mcp_proxy_adapter/examples/examples/full_application/main.py +173 -0
  89. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +154 -0
  90. mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
  91. mcp_proxy_adapter/examples/full_application/commands/__init__.py +7 -0
  92. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +80 -0
  93. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +90 -0
  94. mcp_proxy_adapter/examples/full_application/hooks/__init__.py +7 -0
  95. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +75 -0
  96. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +71 -0
  97. mcp_proxy_adapter/examples/full_application/main.py +173 -0
  98. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +154 -0
  99. mcp_proxy_adapter/examples/generate_all_certificates.py +362 -0
  100. mcp_proxy_adapter/examples/generate_certificates.py +177 -0
  101. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +369 -0
  102. mcp_proxy_adapter/examples/generate_test_configs.py +331 -0
  103. mcp_proxy_adapter/examples/proxy_registration_example.py +334 -0
  104. mcp_proxy_adapter/examples/run_example.py +59 -0
  105. mcp_proxy_adapter/examples/run_full_test_suite.py +318 -0
  106. mcp_proxy_adapter/examples/run_proxy_server.py +146 -0
  107. mcp_proxy_adapter/examples/run_security_tests.py +544 -0
  108. mcp_proxy_adapter/examples/run_security_tests_fixed.py +247 -0
  109. mcp_proxy_adapter/examples/scripts/config_generator.py +740 -0
  110. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +560 -0
  111. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +369 -0
  112. mcp_proxy_adapter/examples/security_test_client.py +782 -0
  113. mcp_proxy_adapter/examples/setup_test_environment.py +328 -0
  114. mcp_proxy_adapter/examples/test_config.py +148 -0
  115. mcp_proxy_adapter/examples/test_config_generator.py +86 -0
  116. mcp_proxy_adapter/examples/test_examples.py +281 -0
  117. mcp_proxy_adapter/examples/universal_client.py +620 -0
  118. mcp_proxy_adapter/main.py +93 -0
  119. mcp_proxy_adapter/utils/config_generator.py +1008 -0
  120. mcp_proxy_adapter/version.py +5 -2
  121. mcp_proxy_adapter-6.0.1.dist-info/METADATA +679 -0
  122. mcp_proxy_adapter-6.0.1.dist-info/RECORD +140 -0
  123. mcp_proxy_adapter-6.0.1.dist-info/entry_points.txt +2 -0
  124. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/licenses/LICENSE +2 -2
  125. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  126. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  127. mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
  128. mcp_proxy_adapter/examples/README.md +0 -124
  129. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  130. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  131. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  132. mcp_proxy_adapter/examples/basic_server/config.json +0 -35
  133. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  134. mcp_proxy_adapter/examples/basic_server/server.py +0 -103
  135. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  136. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  137. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -250
  138. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  139. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  140. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  141. mcp_proxy_adapter/examples/custom_commands/config.json +0 -35
  142. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  143. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  144. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  145. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  146. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  147. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  148. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  149. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  150. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  151. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  152. mcp_proxy_adapter/examples/custom_commands/server.py +0 -228
  153. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  154. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  155. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  156. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  157. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  158. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  159. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  160. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  161. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  162. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  163. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  164. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  165. mcp_proxy_adapter/tests/__init__.py +0 -0
  166. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  167. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  168. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  169. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  170. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  171. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  172. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  173. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  174. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  175. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  176. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  177. mcp_proxy_adapter/tests/conftest.py +0 -131
  178. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  179. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  180. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  181. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  182. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  183. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  184. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  185. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  186. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  187. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  188. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  189. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  190. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  191. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  192. mcp_proxy_adapter/tests/test_config.py +0 -127
  193. mcp_proxy_adapter/tests/test_utils.py +0 -65
  194. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  195. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  196. mcp_proxy_adapter/tests/unit/test_config.py +0 -217
  197. mcp_proxy_adapter-4.1.1.dist-info/METADATA +0 -200
  198. mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
  199. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/WHEEL +0 -0
  200. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Debug Request State - Проверка request.state
4
+ Этот скрипт проверяет, как middleware устанавливает информацию о пользователе в request.state.
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 fastapi import FastAPI, Request
16
+ from fastapi.testclient import TestClient
17
+ from mcp_proxy_adapter.api.app import create_app
18
+ async def debug_request_state():
19
+ """Debug request state handling."""
20
+ print("🔍 ОТЛАДКА REQUEST.STATE")
21
+ print("=" * 50)
22
+ # Create test app with proper configuration
23
+ config_path = project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "config_http_token.json"
24
+ with open(config_path) as f:
25
+ config = json.load(f)
26
+ # Override global config for testing
27
+ import mcp_proxy_adapter.config
28
+ mcp_proxy_adapter.config.config = config
29
+ app = create_app(config)
30
+ client = TestClient(app)
31
+ print("📋 1. ТЕСТИРОВАНИЕ БЕЗ АУТЕНТИФИКАЦИИ")
32
+ print("-" * 30)
33
+ # Test without authentication
34
+ response = client.post("/cmd", json={
35
+ "jsonrpc": "2.0",
36
+ "method": "echo",
37
+ "params": {"message": "test"},
38
+ "id": 1
39
+ })
40
+ print(f"Status: {response.status_code}")
41
+ print(f"Response: {response.json()}")
42
+ print("\n📋 2. ТЕСТИРОВАНИЕ С ADMIN ТОКЕНОМ")
43
+ print("-" * 30)
44
+ # Test with admin token
45
+ response = client.post("/cmd",
46
+ json={
47
+ "jsonrpc": "2.0",
48
+ "method": "echo",
49
+ "params": {"message": "test"},
50
+ "id": 1
51
+ },
52
+ headers={"X-API-Key": "test-token-123"}
53
+ )
54
+ print(f"Status: {response.status_code}")
55
+ print(f"Response: {response.json()}")
56
+ print("\n📋 3. ТЕСТИРОВАНИЕ С USER ТОКЕНОМ")
57
+ print("-" * 30)
58
+ # Test with user token
59
+ response = client.post("/cmd",
60
+ json={
61
+ "jsonrpc": "2.0",
62
+ "method": "echo",
63
+ "params": {"message": "test"},
64
+ "id": 1
65
+ },
66
+ headers={"X-API-Key": "user-token-456"}
67
+ )
68
+ print(f"Status: {response.status_code}")
69
+ print(f"Response: {response.json()}")
70
+ print("\n📋 4. ТЕСТИРОВАНИЕ С READONLY ТОКЕНОМ")
71
+ print("-" * 30)
72
+ # Test with readonly token
73
+ response = client.post("/cmd",
74
+ json={
75
+ "jsonrpc": "2.0",
76
+ "method": "echo",
77
+ "params": {"message": "test"},
78
+ "id": 1
79
+ },
80
+ headers={"X-API-Key": "readonly-token-123"}
81
+ )
82
+ print(f"Status: {response.status_code}")
83
+ print(f"Response: {response.json()}")
84
+ print("\n📋 5. ТЕСТИРОВАНИЕ ROLE_TEST КОМАНДЫ")
85
+ print("-" * 30)
86
+ # Test role_test command with readonly token
87
+ response = client.post("/cmd",
88
+ json={
89
+ "jsonrpc": "2.0",
90
+ "method": "role_test",
91
+ "params": {"action": "write"},
92
+ "id": 1
93
+ },
94
+ headers={"X-API-Key": "readonly-token-123"}
95
+ )
96
+ print(f"Status: {response.status_code}")
97
+ print(f"Response: {response.json()}")
98
+ print("\n📋 6. АНАЛИЗ ПРОБЛЕМЫ")
99
+ print("-" * 30)
100
+ print("🔍 ПРОБЛЕМА: Readonly роль получает доступ к командам")
101
+ print("\n📋 ВОЗМОЖНЫЕ ПРИЧИНЫ:")
102
+ print("1. Framework middleware не устанавливает user info в request.state")
103
+ print("2. Нет проверки прав на уровне middleware")
104
+ print("3. Команды не проверяют права доступа")
105
+ print("4. Интеграция между middleware и командами не работает")
106
+ print("\n📋 РЕКОМЕНДАЦИИ:")
107
+ print("1. Добавить CommandPermissionMiddleware")
108
+ print("2. Убедиться, что framework middleware устанавливает user info")
109
+ print("3. Добавить проверку прав в команды")
110
+ print("4. Проверить интеграцию middleware")
111
+ if __name__ == "__main__":
112
+ asyncio.run(debug_request_state())
@@ -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