mcp-proxy-adapter 6.3.3__py3-none-any.whl → 6.3.5__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 (129) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +108 -88
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +12 -2
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.5.dist-info/RECORD +143 -0
  125. mcp_proxy_adapter-6.3.3.dist-info/RECORD +0 -143
  126. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
  127. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
  128. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
  129. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -9,89 +9,106 @@ import asyncio
9
9
  import json
10
10
  import sys
11
11
  from pathlib import Path
12
+
12
13
  # Add project root to path
13
14
  project_root = Path(__file__).parent.parent.parent
14
15
  sys.path.insert(0, str(project_root))
15
16
  from fastapi import FastAPI, Request
16
17
  from fastapi.testclient import TestClient
17
18
  from mcp_proxy_adapter.api.app import create_app
19
+
20
+
18
21
  async def debug_request_state():
19
22
  """Debug request state handling."""
20
23
  print("🔍 ОТЛАДКА REQUEST.STATE")
21
24
  print("=" * 50)
22
25
  # Create test app with proper configuration
23
- config_path = project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "config_http_token.json"
26
+ config_path = (
27
+ project_root
28
+ / "mcp_proxy_adapter"
29
+ / "examples"
30
+ / "server_configs"
31
+ / "config_http_token.json"
32
+ )
24
33
  with open(config_path) as f:
25
34
  config = json.load(f)
26
35
  # Override global config for testing
27
36
  import mcp_proxy_adapter.config
37
+
28
38
  mcp_proxy_adapter.config.config = config
29
39
  app = create_app(config)
30
40
  client = TestClient(app)
31
41
  print("📋 1. ТЕСТИРОВАНИЕ БЕЗ АУТЕНТИФИКАЦИИ")
32
42
  print("-" * 30)
33
43
  # Test without authentication
34
- response = client.post("/cmd", json={
35
- "jsonrpc": "2.0",
36
- "method": "echo",
37
- "params": {"message": "test"},
38
- "id": 1
39
- })
44
+ response = client.post(
45
+ "/cmd",
46
+ json={
47
+ "jsonrpc": "2.0",
48
+ "method": "echo",
49
+ "params": {"message": "test"},
50
+ "id": 1,
51
+ },
52
+ )
40
53
  print(f"Status: {response.status_code}")
41
54
  print(f"Response: {response.json()}")
42
55
  print("\n📋 2. ТЕСТИРОВАНИЕ С ADMIN ТОКЕНОМ")
43
56
  print("-" * 30)
44
57
  # Test with admin token
45
- response = client.post("/cmd",
58
+ response = client.post(
59
+ "/cmd",
46
60
  json={
47
61
  "jsonrpc": "2.0",
48
62
  "method": "echo",
49
63
  "params": {"message": "test"},
50
- "id": 1
64
+ "id": 1,
51
65
  },
52
- headers={"X-API-Key": "test-token-123"}
66
+ headers={"X-API-Key": "test-token-123"},
53
67
  )
54
68
  print(f"Status: {response.status_code}")
55
69
  print(f"Response: {response.json()}")
56
70
  print("\n📋 3. ТЕСТИРОВАНИЕ С USER ТОКЕНОМ")
57
71
  print("-" * 30)
58
72
  # Test with user token
59
- response = client.post("/cmd",
73
+ response = client.post(
74
+ "/cmd",
60
75
  json={
61
76
  "jsonrpc": "2.0",
62
77
  "method": "echo",
63
78
  "params": {"message": "test"},
64
- "id": 1
79
+ "id": 1,
65
80
  },
66
- headers={"X-API-Key": "user-token-456"}
81
+ headers={"X-API-Key": "user-token-456"},
67
82
  )
68
83
  print(f"Status: {response.status_code}")
69
84
  print(f"Response: {response.json()}")
70
85
  print("\n📋 4. ТЕСТИРОВАНИЕ С READONLY ТОКЕНОМ")
71
86
  print("-" * 30)
72
87
  # Test with readonly token
73
- response = client.post("/cmd",
88
+ response = client.post(
89
+ "/cmd",
74
90
  json={
75
91
  "jsonrpc": "2.0",
76
92
  "method": "echo",
77
93
  "params": {"message": "test"},
78
- "id": 1
94
+ "id": 1,
79
95
  },
80
- headers={"X-API-Key": "readonly-token-123"}
96
+ headers={"X-API-Key": "readonly-token-123"},
81
97
  )
82
98
  print(f"Status: {response.status_code}")
83
99
  print(f"Response: {response.json()}")
84
100
  print("\n📋 5. ТЕСТИРОВАНИЕ ROLE_TEST КОМАНДЫ")
85
101
  print("-" * 30)
86
102
  # Test role_test command with readonly token
87
- response = client.post("/cmd",
103
+ response = client.post(
104
+ "/cmd",
88
105
  json={
89
106
  "jsonrpc": "2.0",
90
107
  "method": "role_test",
91
108
  "params": {"action": "write"},
92
- "id": 1
109
+ "id": 1,
93
110
  },
94
- headers={"X-API-Key": "readonly-token-123"}
111
+ headers={"X-API-Key": "readonly-token-123"},
95
112
  )
96
113
  print(f"Status: {response.status_code}")
97
114
  print(f"Response: {response.json()}")
@@ -108,5 +125,7 @@ async def debug_request_state():
108
125
  print("2. Убедиться, что framework middleware устанавливает user info")
109
126
  print("3. Добавить проверку прав в команды")
110
127
  print("4. Проверить интеграцию middleware")
128
+
129
+
111
130
  if __name__ == "__main__":
112
131
  asyncio.run(debug_request_state())
@@ -9,17 +9,30 @@ import asyncio
9
9
  import json
10
10
  import sys
11
11
  from pathlib import Path
12
+
12
13
  # Add project root to path
13
14
  project_root = Path(__file__).parent.parent.parent
14
15
  sys.path.insert(0, str(project_root))
15
16
  from mcp_security_framework import SecurityManager, AuthManager, PermissionManager
16
- from mcp_security_framework.schemas.config import SecurityConfig, AuthConfig, PermissionConfig
17
+ from mcp_security_framework.schemas.config import (
18
+ SecurityConfig,
19
+ AuthConfig,
20
+ PermissionConfig,
21
+ )
22
+
23
+
17
24
  async def debug_role_chain():
18
25
  """Debug the complete role chain from authentication to blocking."""
19
26
  print("🔍 АНАЛИЗ ЦЕПОЧКИ БЛОКИРОВКИ РОЛЕЙ")
20
27
  print("=" * 60)
21
28
  # Load configuration
22
- config_path = project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "config_http_token.json"
29
+ config_path = (
30
+ project_root
31
+ / "mcp_proxy_adapter"
32
+ / "examples"
33
+ / "server_configs"
34
+ / "config_http_token.json"
35
+ )
23
36
  with open(config_path) as f:
24
37
  config = json.load(f)
25
38
  security_config = config.get("security", {})
@@ -37,7 +50,13 @@ async def debug_role_chain():
37
50
  print("-" * 30)
38
51
  # Create permission config
39
52
  perm_config = PermissionConfig(
40
- roles_file=str(project_root / "mcp_proxy_adapter" / "examples" / "server_configs" / "roles.json"),
53
+ roles_file=str(
54
+ project_root
55
+ / "mcp_proxy_adapter"
56
+ / "examples"
57
+ / "server_configs"
58
+ / "roles.json"
59
+ ),
41
60
  default_role="guest",
42
61
  admin_role="admin",
43
62
  role_hierarchy=security_config.get("permissions", {}).get("role_hierarchy", {}),
@@ -45,7 +64,7 @@ async def debug_role_chain():
45
64
  permission_cache_ttl=300,
46
65
  wildcard_permissions=False,
47
66
  strict_mode=True,
48
- roles=roles_config
67
+ roles=roles_config,
49
68
  )
50
69
  # Create auth config
51
70
  auth_config = AuthConfig(
@@ -57,17 +76,18 @@ async def debug_role_chain():
57
76
  jwt_algorithm=security_config.get("auth", {}).get("jwt_algorithm", "HS256"),
58
77
  jwt_expiry_hours=security_config.get("auth", {}).get("jwt_expiry_hours", 24),
59
78
  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"),
79
+ certificate_roles_oid=security_config.get("auth", {}).get(
80
+ "certificate_roles_oid"
81
+ ),
82
+ certificate_permissions_oid=security_config.get("auth", {}).get(
83
+ "certificate_permissions_oid"
84
+ ),
62
85
  basic_auth=security_config.get("auth", {}).get("basic_auth", False),
63
86
  oauth2_config=security_config.get("auth", {}).get("oauth2_config"),
64
- public_paths=security_config.get("auth", {}).get("public_paths", [])
87
+ public_paths=security_config.get("auth", {}).get("public_paths", []),
65
88
  )
66
89
  # Create security config
67
- security_config_obj = SecurityConfig(
68
- auth=auth_config,
69
- permissions=perm_config
70
- )
90
+ security_config_obj = SecurityConfig(auth=auth_config, permissions=perm_config)
71
91
  print("✅ Конфигурации созданы")
72
92
  print("\n📋 4. ИНИЦИАЛИЗАЦИЯ МЕНЕДЖЕРОВ")
73
93
  print("-" * 30)
@@ -83,7 +103,7 @@ async def debug_role_chain():
83
103
  "admin": "test-token-123",
84
104
  "user": "user-token-456",
85
105
  "readonly": "readonly-token-123",
86
- "invalid": "invalid-token-999"
106
+ "invalid": "invalid-token-999",
87
107
  }
88
108
  auth_results = {}
89
109
  for role, token in test_tokens.items():
@@ -91,7 +111,9 @@ async def debug_role_chain():
91
111
  try:
92
112
  result = auth_manager.authenticate_api_key(token)
93
113
  auth_results[role] = result
94
- print(f" ✅ Аутентификация: {'УСПЕШНА' if result.is_valid else 'НЕУДАЧНА'}")
114
+ print(
115
+ f" ✅ Аутентификация: {'УСПЕШНА' if result.is_valid else 'НЕУДАЧНА'}"
116
+ )
95
117
  if result.is_valid:
96
118
  print(f" 👤 Пользователь: {result.username}")
97
119
  print(f" 🏷️ Роли: {result.roles}")
@@ -107,20 +129,29 @@ async def debug_role_chain():
107
129
  test_actions = ["read", "write", "manage", "delete"]
108
130
  for role, auth_result in auth_results.items():
109
131
  if auth_result and auth_result.is_valid:
110
- print(f"\n🔒 Тестирование прав для роли '{role}' (роли: {auth_result.roles})")
132
+ print(
133
+ f"\n🔒 Тестирование прав для роли '{role}' (роли: {auth_result.roles})"
134
+ )
111
135
  for action in test_actions:
112
136
  try:
113
137
  # Check permissions using permission manager
114
138
  validation_result = permission_manager.validate_access(
115
- auth_result.roles,
116
- [action]
139
+ auth_result.roles, [action]
140
+ )
141
+ status = (
142
+ "✅ РАЗРЕШЕНО"
143
+ if validation_result.is_valid
144
+ else "❌ ЗАБЛОКИРОВАНО"
117
145
  )
118
- status = "✅ РАЗРЕШЕНО" if validation_result.is_valid else "❌ ЗАБЛОКИРОВАНО"
119
146
  print(f" {action}: {status}")
120
147
  if not validation_result.is_valid:
121
148
  print(f" 📝 Причина: {validation_result.error_message}")
122
- print(f" 🎯 Эффективные права: {validation_result.effective_permissions}")
123
- print(f" Отсутствующие права: {validation_result.missing_permissions}")
149
+ print(
150
+ f" 🎯 Эффективные права: {validation_result.effective_permissions}"
151
+ )
152
+ print(
153
+ f" ❌ Отсутствующие права: {validation_result.missing_permissions}"
154
+ )
124
155
  except Exception as e:
125
156
  print(f" {action}: ❌ ОШИБКА - {e}")
126
157
  print("\n📋 7. ТЕСТИРОВАНИЕ ПОЛНОЙ ЦЕПОЧКИ")
@@ -131,7 +162,7 @@ async def debug_role_chain():
131
162
  request_data = {
132
163
  "api_key": token,
133
164
  "required_permissions": ["write"],
134
- "client_ip": "127.0.0.1"
165
+ "client_ip": "127.0.0.1",
135
166
  }
136
167
  try:
137
168
  result = security_manager.validate_request(request_data)
@@ -154,5 +185,7 @@ async def debug_role_chain():
154
185
  print("2. Добавить проверку прав на уровне middleware")
155
186
  print("3. Убедиться, что request.state содержит user info")
156
187
  print("4. Проверить интеграцию между middleware и командами")
188
+
189
+
157
190
  if __name__ == "__main__":
158
191
  asyncio.run(debug_role_chain())
@@ -5,13 +5,17 @@ authentication methods and connection types.
5
5
  Author: Vasiliy Zdanovskiy
6
6
  email: vasilyvz@gmail.com
7
7
  """
8
+
8
9
  import asyncio
9
10
  import json
10
11
  import sys
11
12
  from pathlib import Path
13
+
12
14
  # Add project root to path
13
15
  sys.path.insert(0, str(Path(__file__).parent.parent))
14
16
  from examples.universal_client import UniversalClient, create_client_config
17
+
18
+
15
19
  async def demo_from_config_file(config_file: str):
16
20
  """
17
21
  Demo client using configuration from file.
@@ -22,9 +26,11 @@ async def demo_from_config_file(config_file: str):
22
26
  print("=" * 50)
23
27
  try:
24
28
  # Load configuration
25
- with open(config_file, 'r') as f:
29
+ with open(config_file, "r") as f:
26
30
  config = json.load(f)
27
- print(f"Configuration loaded: {config.get('security', {}).get('auth_method', 'none')} auth")
31
+ print(
32
+ f"Configuration loaded: {config.get('security', {}).get('auth_method', 'none')} auth"
33
+ )
28
34
  # Create and use client
29
35
  async with UniversalClient(config) as client:
30
36
  # Test connection
@@ -47,6 +53,8 @@ async def demo_from_config_file(config_file: str):
47
53
  print(f"❌ Invalid JSON in configuration file: {config_file}")
48
54
  except Exception as e:
49
55
  print(f"❌ Demo failed: {e}")
56
+
57
+
50
58
  async def demo_api_calls(client: UniversalClient):
51
59
  """Demonstrate various API calls."""
52
60
  print("\n📡 API Calls Demo:")
@@ -70,9 +78,9 @@ async def demo_api_calls(client: UniversalClient):
70
78
  "method": "test_command",
71
79
  "params": {
72
80
  "message": "Hello from universal client!",
73
- "timestamp": "2024-01-01T00:00:00Z"
81
+ "timestamp": "2024-01-01T00:00:00Z",
74
82
  },
75
- "id": 1
83
+ "id": 1,
76
84
  }
77
85
  result = await client.post("/api/jsonrpc", command_data)
78
86
  print(f"Command Result: {result}")
@@ -83,16 +91,15 @@ async def demo_api_calls(client: UniversalClient):
83
91
  security_data = {
84
92
  "jsonrpc": "2.0",
85
93
  "method": "security_command",
86
- "params": {
87
- "action": "get_status",
88
- "include_certificates": True
89
- },
90
- "id": 2
94
+ "params": {"action": "get_status", "include_certificates": True},
95
+ "id": 2,
91
96
  }
92
97
  result = await client.post("/api/jsonrpc", security_data)
93
98
  print(f"Security Status: {result}")
94
99
  except Exception as e:
95
100
  print(f"Security command failed: {e}")
101
+
102
+
96
103
  async def demo_all_configs():
97
104
  """Demo all available client configurations."""
98
105
  print("🚀 Demo All Client Configurations")
@@ -112,6 +119,8 @@ async def demo_all_configs():
112
119
  for config_file in config_files:
113
120
  await demo_from_config_file(str(config_file))
114
121
  print("\n" + "-" * 50)
122
+
123
+
115
124
  async def demo_programmatic_config():
116
125
  """Demo client with programmatically created configuration."""
117
126
  print("🚀 Demo Programmatic Configuration")
@@ -121,10 +130,8 @@ async def demo_programmatic_config():
121
130
  {
122
131
  "name": "API Key Client",
123
132
  "config": create_client_config(
124
- "http://localhost:8000",
125
- "api_key",
126
- api_key="demo_api_key_123"
127
- )
133
+ "http://localhost:8000", "api_key", api_key="demo_api_key_123"
134
+ ),
128
135
  },
129
136
  {
130
137
  "name": "JWT Client",
@@ -133,8 +140,8 @@ async def demo_programmatic_config():
133
140
  "jwt",
134
141
  username="demo_user",
135
142
  password="demo_password",
136
- secret="demo_jwt_secret"
137
- )
143
+ secret="demo_jwt_secret",
144
+ ),
138
145
  },
139
146
  {
140
147
  "name": "Certificate Client",
@@ -143,8 +150,8 @@ async def demo_programmatic_config():
143
150
  "certificate",
144
151
  cert_file="./certs/client.crt",
145
152
  key_file="./keys/client.key",
146
- ca_cert_file="./certs/ca.crt"
147
- )
153
+ ca_cert_file="./certs/ca.crt",
154
+ ),
148
155
  },
149
156
  {
150
157
  "name": "Basic Auth Client",
@@ -152,9 +159,9 @@ async def demo_programmatic_config():
152
159
  "http://localhost:8000",
153
160
  "basic",
154
161
  username="demo_user",
155
- password="demo_password"
156
- )
157
- }
162
+ password="demo_password",
163
+ ),
164
+ },
158
165
  ]
159
166
  for config_info in configs:
160
167
  print(f"\n📋 Testing: {config_info['name']}")
@@ -169,6 +176,8 @@ async def demo_programmatic_config():
169
176
  print("❌ Connection failed")
170
177
  except Exception as e:
171
178
  print(f"❌ Test failed: {e}")
179
+
180
+
172
181
  async def interactive_demo():
173
182
  """Interactive demo with user input."""
174
183
  print("🚀 Interactive Client Demo")
@@ -186,14 +195,16 @@ async def interactive_demo():
186
195
  "2": "api_key",
187
196
  "3": "jwt",
188
197
  "4": "certificate",
189
- "5": "basic"
198
+ "5": "basic",
190
199
  }
191
200
  if choice not in auth_methods:
192
201
  print("❌ Invalid choice")
193
202
  return
194
203
  auth_method = auth_methods[choice]
195
204
  # Get server URL
196
- server_url = input("Enter server URL (default: http://localhost:8000): ").strip()
205
+ server_url = input(
206
+ "Enter server URL (default: http://localhost:8000): "
207
+ ).strip()
197
208
  if not server_url:
198
209
  server_url = "http://localhost:8000"
199
210
  # Create configuration based on choice
@@ -207,29 +218,26 @@ async def interactive_demo():
207
218
  password = input("Enter password: ").strip()
208
219
  secret = input("Enter JWT secret: ").strip()
209
220
  if username and password and secret:
210
- config_kwargs.update({
211
- "username": username,
212
- "password": password,
213
- "secret": secret
214
- })
221
+ config_kwargs.update(
222
+ {"username": username, "password": password, "secret": secret}
223
+ )
215
224
  elif auth_method == "certificate":
216
225
  cert_file = input("Enter certificate file path: ").strip()
217
226
  key_file = input("Enter key file path: ").strip()
218
227
  ca_cert_file = input("Enter CA certificate file path: ").strip()
219
228
  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
- })
229
+ config_kwargs.update(
230
+ {
231
+ "cert_file": cert_file,
232
+ "key_file": key_file,
233
+ "ca_cert_file": ca_cert_file,
234
+ }
235
+ )
225
236
  elif auth_method == "basic":
226
237
  username = input("Enter username: ").strip()
227
238
  password = input("Enter password: ").strip()
228
239
  if username and password:
229
- config_kwargs.update({
230
- "username": username,
231
- "password": password
232
- })
240
+ config_kwargs.update({"username": username, "password": password})
233
241
  # Create configuration
234
242
  config = create_client_config(server_url, auth_method, **config_kwargs)
235
243
  print(f"\nConfiguration created for {auth_method} authentication")
@@ -246,6 +254,8 @@ async def interactive_demo():
246
254
  print("\n\nDemo interrupted by user")
247
255
  except Exception as e:
248
256
  print(f"❌ Interactive demo failed: {e}")
257
+
258
+
249
259
  def main():
250
260
  """Main demo function."""
251
261
  if len(sys.argv) > 1:
@@ -271,5 +281,7 @@ def main():
271
281
  else:
272
282
  # Default: demo all configs
273
283
  asyncio.run(demo_all_configs())
284
+
285
+
274
286
  if __name__ == "__main__":
275
287
  main()
@@ -9,13 +9,18 @@ email: vasilyvz@gmail.com
9
9
  import sys
10
10
  import argparse
11
11
  from pathlib import Path
12
+
12
13
  # Add the framework to the path
13
14
  sys.path.insert(0, str(Path(__file__).parent.parent.parent))
14
15
  from mcp_proxy_adapter.core.app_factory import create_and_run_server
16
+
17
+
15
18
  def main():
16
19
  """Main entry point for the basic framework example."""
17
20
  parser = argparse.ArgumentParser(description="Basic Framework Example")
18
- parser.add_argument("--config", "-c", required=True, help="Path to configuration file")
21
+ parser.add_argument(
22
+ "--config", "-c", required=True, help="Path to configuration file"
23
+ )
19
24
  parser.add_argument("--host", help="Server host")
20
25
  parser.add_argument("--port", type=int, help="Server port")
21
26
  parser.add_argument("--debug", action="store_true", help="Enable debug mode")
@@ -38,7 +43,9 @@ def main():
38
43
  description="Basic MCP Proxy Adapter with minimal configuration",
39
44
  version="1.0.0",
40
45
  host=config_overrides.get("host", "0.0.0.0"),
41
- log_level="debug" if config_overrides.get("debug", False) else "info"
46
+ log_level="debug" if config_overrides.get("debug", False) else "info",
42
47
  )
48
+
49
+
43
50
  if __name__ == "__main__":
44
51
  main()
@@ -8,5 +8,6 @@ This example demonstrates advanced usage of MCP Proxy Adapter including:
8
8
  """
9
9
 
10
10
  from .main import get_app
11
+
11
12
  app = get_app()
12
13
  from .proxy_endpoints import router as proxy_router
@@ -4,23 +4,29 @@ This module demonstrates a custom command implementation for the full applicatio
4
4
  Author: Vasiliy Zdanovskiy
5
5
  email: vasilyvz@gmail.com
6
6
  """
7
+
7
8
  from typing import Dict, Any, Optional
8
9
  from mcp_proxy_adapter.commands.base import BaseCommand
9
10
  from mcp_proxy_adapter.commands.result import CommandResult
11
+
12
+
10
13
  class CustomEchoResult(CommandResult):
11
14
  """Result class for custom echo command."""
15
+
12
16
  def __init__(self, message: str, timestamp: str, echo_count: int):
13
17
  self.message = message
14
18
  self.timestamp = timestamp
15
19
  self.echo_count = echo_count
20
+
16
21
  def to_dict(self) -> Dict[str, Any]:
17
22
  """Convert result to dictionary."""
18
23
  return {
19
24
  "message": self.message,
20
25
  "timestamp": self.timestamp,
21
26
  "echo_count": self.echo_count,
22
- "command_type": "custom_echo"
27
+ "command_type": "custom_echo",
23
28
  }
29
+
24
30
  def get_schema(self) -> Dict[str, Any]:
25
31
  """Get result schema."""
26
32
  return {
@@ -29,21 +35,27 @@ class CustomEchoResult(CommandResult):
29
35
  "message": {"type": "string", "description": "Echoed message"},
30
36
  "timestamp": {"type": "string", "description": "Timestamp of echo"},
31
37
  "echo_count": {"type": "integer", "description": "Number of echoes"},
32
- "command_type": {"type": "string", "description": "Command type"}
38
+ "command_type": {"type": "string", "description": "Command type"},
33
39
  },
34
- "required": ["message", "timestamp", "echo_count", "command_type"]
40
+ "required": ["message", "timestamp", "echo_count", "command_type"],
35
41
  }
42
+
43
+
36
44
  class CustomEchoCommand(BaseCommand):
37
45
  """Custom echo command implementation."""
46
+
38
47
  def __init__(self):
39
48
  super().__init__()
40
49
  self.echo_count = 0
50
+
41
51
  def get_name(self) -> str:
42
52
  """Get command name."""
43
53
  return "custom_echo"
54
+
44
55
  def get_description(self) -> str:
45
56
  """Get command description."""
46
57
  return "Custom echo command with enhanced features"
58
+
47
59
  def get_schema(self) -> Dict[str, Any]:
48
60
  """Get command schema."""
49
61
  return {
@@ -52,29 +64,29 @@ class CustomEchoCommand(BaseCommand):
52
64
  "message": {
53
65
  "type": "string",
54
66
  "description": "Message to echo",
55
- "default": "Hello from custom echo!"
67
+ "default": "Hello from custom echo!",
56
68
  },
57
69
  "repeat": {
58
70
  "type": "integer",
59
71
  "description": "Number of times to repeat",
60
72
  "default": 1,
61
73
  "minimum": 1,
62
- "maximum": 10
63
- }
74
+ "maximum": 10,
75
+ },
64
76
  },
65
- "required": ["message"]
77
+ "required": ["message"],
66
78
  }
79
+
67
80
  async def execute(self, params: Dict[str, Any]) -> CustomEchoResult:
68
81
  """Execute the custom echo command."""
69
82
  message = params.get("message", "Hello from custom echo!")
70
83
  repeat = min(max(params.get("repeat", 1), 1), 10)
71
84
  self.echo_count += 1
72
85
  from datetime import datetime
86
+
73
87
  timestamp = datetime.now().isoformat()
74
88
  # Repeat the message
75
89
  echoed_message = " ".join([message] * repeat)
76
90
  return CustomEchoResult(
77
- message=echoed_message,
78
- timestamp=timestamp,
79
- echo_count=self.echo_count
91
+ message=echoed_message, timestamp=timestamp, echo_count=self.echo_count
80
92
  )