mcp-proxy-adapter 6.0.0__py3-none-any.whl → 6.1.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 (264) hide show
  1. mcp_proxy_adapter/api/app.py +174 -80
  2. mcp_proxy_adapter/api/handlers.py +16 -5
  3. mcp_proxy_adapter/api/middleware/__init__.py +9 -4
  4. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +148 -0
  5. mcp_proxy_adapter/api/middleware/factory.py +36 -12
  6. mcp_proxy_adapter/api/middleware/protocol_middleware.py +32 -13
  7. mcp_proxy_adapter/api/middleware/unified_security.py +160 -0
  8. mcp_proxy_adapter/api/middleware/user_info_middleware.py +83 -0
  9. mcp_proxy_adapter/commands/__init__.py +7 -1
  10. mcp_proxy_adapter/commands/base.py +7 -4
  11. mcp_proxy_adapter/commands/builtin_commands.py +8 -2
  12. mcp_proxy_adapter/commands/command_registry.py +8 -0
  13. mcp_proxy_adapter/commands/echo_command.py +81 -0
  14. mcp_proxy_adapter/commands/help_command.py +21 -14
  15. mcp_proxy_adapter/commands/proxy_registration_command.py +326 -185
  16. mcp_proxy_adapter/commands/role_test_command.py +141 -0
  17. mcp_proxy_adapter/commands/security_command.py +488 -0
  18. mcp_proxy_adapter/commands/ssl_setup_command.py +2 -2
  19. mcp_proxy_adapter/commands/token_management_command.py +1 -1
  20. mcp_proxy_adapter/config.py +81 -21
  21. mcp_proxy_adapter/core/app_factory.py +326 -0
  22. mcp_proxy_adapter/core/client_security.py +384 -0
  23. mcp_proxy_adapter/core/logging.py +8 -3
  24. mcp_proxy_adapter/core/mtls_asgi.py +156 -0
  25. mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
  26. mcp_proxy_adapter/core/protocol_manager.py +139 -8
  27. mcp_proxy_adapter/core/proxy_client.py +602 -0
  28. mcp_proxy_adapter/core/proxy_registration.py +299 -47
  29. mcp_proxy_adapter/core/security_adapter.py +12 -15
  30. mcp_proxy_adapter/core/security_integration.py +285 -0
  31. mcp_proxy_adapter/core/server_adapter.py +345 -0
  32. mcp_proxy_adapter/core/server_engine.py +364 -0
  33. mcp_proxy_adapter/core/unified_config_adapter.py +579 -0
  34. mcp_proxy_adapter/docs/EN/TROUBLESHOOTING.md +285 -0
  35. mcp_proxy_adapter/docs/RU/TROUBLESHOOTING.md +285 -0
  36. mcp_proxy_adapter/examples/README.md +230 -97
  37. mcp_proxy_adapter/examples/README_EN.md +258 -0
  38. mcp_proxy_adapter/examples/SECURITY_TESTING.md +455 -0
  39. mcp_proxy_adapter/examples/basic_framework/configs/http_auth.json +37 -0
  40. mcp_proxy_adapter/examples/basic_framework/configs/http_simple.json +23 -0
  41. mcp_proxy_adapter/examples/basic_framework/configs/https_auth.json +43 -0
  42. mcp_proxy_adapter/examples/basic_framework/configs/https_no_protocol_middleware.json +36 -0
  43. mcp_proxy_adapter/examples/basic_framework/configs/https_simple.json +29 -0
  44. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_protocol_middleware.json +34 -0
  45. mcp_proxy_adapter/examples/basic_framework/configs/mtls_no_roles.json +39 -0
  46. mcp_proxy_adapter/examples/basic_framework/configs/mtls_simple.json +35 -0
  47. mcp_proxy_adapter/examples/basic_framework/configs/mtls_with_roles.json +45 -0
  48. mcp_proxy_adapter/examples/basic_framework/main.py +63 -0
  49. mcp_proxy_adapter/examples/basic_framework/roles.json +21 -0
  50. mcp_proxy_adapter/examples/cert_config.json +9 -0
  51. mcp_proxy_adapter/examples/certs/admin.crt +32 -0
  52. mcp_proxy_adapter/examples/certs/admin.key +52 -0
  53. mcp_proxy_adapter/examples/certs/admin_cert.pem +21 -0
  54. mcp_proxy_adapter/examples/certs/admin_key.pem +28 -0
  55. mcp_proxy_adapter/examples/certs/ca_cert.pem +23 -0
  56. mcp_proxy_adapter/examples/certs/ca_cert.srl +1 -0
  57. mcp_proxy_adapter/examples/certs/ca_key.pem +28 -0
  58. mcp_proxy_adapter/examples/certs/cert_config.json +9 -0
  59. mcp_proxy_adapter/examples/certs/client.crt +32 -0
  60. mcp_proxy_adapter/examples/certs/client.key +52 -0
  61. mcp_proxy_adapter/examples/certs/client_admin.crt +32 -0
  62. mcp_proxy_adapter/examples/certs/client_admin.key +52 -0
  63. mcp_proxy_adapter/examples/certs/client_user.crt +32 -0
  64. mcp_proxy_adapter/examples/certs/client_user.key +52 -0
  65. mcp_proxy_adapter/examples/certs/guest_cert.pem +21 -0
  66. mcp_proxy_adapter/examples/certs/guest_key.pem +28 -0
  67. mcp_proxy_adapter/examples/certs/mcp_proxy_adapter_ca_ca.crt +23 -0
  68. mcp_proxy_adapter/examples/certs/proxy_cert.pem +21 -0
  69. mcp_proxy_adapter/examples/certs/proxy_key.pem +28 -0
  70. mcp_proxy_adapter/examples/certs/readonly.crt +32 -0
  71. mcp_proxy_adapter/examples/certs/readonly.key +52 -0
  72. mcp_proxy_adapter/examples/certs/readonly_cert.pem +21 -0
  73. mcp_proxy_adapter/examples/certs/readonly_key.pem +28 -0
  74. mcp_proxy_adapter/examples/certs/server.crt +32 -0
  75. mcp_proxy_adapter/examples/certs/server.key +52 -0
  76. mcp_proxy_adapter/examples/certs/server_cert.pem +32 -0
  77. mcp_proxy_adapter/examples/certs/server_key.pem +52 -0
  78. mcp_proxy_adapter/examples/certs/test_ca_ca.crt +20 -0
  79. mcp_proxy_adapter/examples/certs/user.crt +32 -0
  80. mcp_proxy_adapter/examples/certs/user.key +52 -0
  81. mcp_proxy_adapter/examples/certs/user_cert.pem +21 -0
  82. mcp_proxy_adapter/examples/certs/user_key.pem +28 -0
  83. mcp_proxy_adapter/examples/client_configs/api_key_client.json +13 -0
  84. mcp_proxy_adapter/examples/client_configs/basic_auth_client.json +13 -0
  85. mcp_proxy_adapter/examples/client_configs/certificate_client.json +22 -0
  86. mcp_proxy_adapter/examples/client_configs/jwt_client.json +15 -0
  87. mcp_proxy_adapter/examples/client_configs/no_auth_client.json +9 -0
  88. mcp_proxy_adapter/examples/commands/__init__.py +1 -0
  89. mcp_proxy_adapter/examples/create_certificates_simple.py +307 -0
  90. mcp_proxy_adapter/examples/debug_request_state.py +144 -0
  91. mcp_proxy_adapter/examples/debug_role_chain.py +205 -0
  92. mcp_proxy_adapter/examples/demo_client.py +341 -0
  93. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +99 -0
  94. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +106 -0
  95. mcp_proxy_adapter/examples/full_application/configs/http_auth.json +37 -0
  96. mcp_proxy_adapter/examples/full_application/configs/http_simple.json +23 -0
  97. mcp_proxy_adapter/examples/full_application/configs/https_auth.json +39 -0
  98. mcp_proxy_adapter/examples/full_application/configs/https_simple.json +25 -0
  99. mcp_proxy_adapter/examples/full_application/configs/mtls_no_roles.json +39 -0
  100. mcp_proxy_adapter/examples/full_application/configs/mtls_with_roles.json +45 -0
  101. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +97 -0
  102. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +95 -0
  103. mcp_proxy_adapter/examples/full_application/main.py +138 -0
  104. mcp_proxy_adapter/examples/full_application/roles.json +21 -0
  105. mcp_proxy_adapter/examples/generate_all_certificates.py +429 -0
  106. mcp_proxy_adapter/examples/generate_certificates.py +121 -0
  107. mcp_proxy_adapter/examples/keys/ca_key.pem +28 -0
  108. mcp_proxy_adapter/examples/keys/mcp_proxy_adapter_ca_ca.key +28 -0
  109. mcp_proxy_adapter/examples/keys/test_ca_ca.key +28 -0
  110. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log +220 -0
  111. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.1 +1 -0
  112. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.2 +1 -0
  113. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.3 +1 -0
  114. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.4 +1 -0
  115. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter.log.5 +1 -0
  116. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log +220 -0
  117. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.1 +1 -0
  118. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.2 +1 -0
  119. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.3 +1 -0
  120. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.4 +1 -0
  121. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_access.log.5 +1 -0
  122. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log +2 -0
  123. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.1 +1 -0
  124. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.2 +1 -0
  125. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.3 +1 -0
  126. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.4 +1 -0
  127. mcp_proxy_adapter/examples/logs/mcp_proxy_adapter_error.log.5 +1 -0
  128. mcp_proxy_adapter/examples/proxy_registration_example.py +401 -0
  129. mcp_proxy_adapter/examples/roles.json +38 -0
  130. mcp_proxy_adapter/examples/run_example.py +81 -0
  131. mcp_proxy_adapter/examples/run_security_tests.py +326 -0
  132. mcp_proxy_adapter/examples/run_security_tests_fixed.py +300 -0
  133. mcp_proxy_adapter/examples/security_test_client.py +743 -0
  134. mcp_proxy_adapter/examples/server_configs/config_basic_http.json +204 -0
  135. mcp_proxy_adapter/examples/server_configs/config_http_token.json +238 -0
  136. mcp_proxy_adapter/examples/server_configs/config_https.json +215 -0
  137. mcp_proxy_adapter/examples/server_configs/config_https_token.json +231 -0
  138. mcp_proxy_adapter/examples/server_configs/config_mtls.json +215 -0
  139. mcp_proxy_adapter/examples/server_configs/config_proxy_registration.json +250 -0
  140. mcp_proxy_adapter/examples/server_configs/config_simple.json +46 -0
  141. mcp_proxy_adapter/examples/server_configs/roles.json +38 -0
  142. mcp_proxy_adapter/examples/test_config_generator.py +110 -0
  143. mcp_proxy_adapter/examples/test_examples.py +344 -0
  144. mcp_proxy_adapter/examples/universal_client.py +628 -0
  145. mcp_proxy_adapter/main.py +21 -10
  146. mcp_proxy_adapter/utils/config_generator.py +727 -0
  147. mcp_proxy_adapter/version.py +5 -2
  148. mcp_proxy_adapter-6.1.1.dist-info/METADATA +205 -0
  149. mcp_proxy_adapter-6.1.1.dist-info/RECORD +197 -0
  150. mcp_proxy_adapter-6.1.1.dist-info/entry_points.txt +2 -0
  151. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/licenses/LICENSE +2 -2
  152. mcp_proxy_adapter/api/middleware/auth.py +0 -146
  153. mcp_proxy_adapter/api/middleware/auth_adapter.py +0 -235
  154. mcp_proxy_adapter/api/middleware/mtls_adapter.py +0 -305
  155. mcp_proxy_adapter/api/middleware/mtls_middleware.py +0 -296
  156. mcp_proxy_adapter/api/middleware/rate_limit.py +0 -152
  157. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +0 -241
  158. mcp_proxy_adapter/api/middleware/roles_adapter.py +0 -365
  159. mcp_proxy_adapter/api/middleware/roles_middleware.py +0 -381
  160. mcp_proxy_adapter/api/middleware/security.py +0 -376
  161. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +0 -261
  162. mcp_proxy_adapter/examples/__init__.py +0 -7
  163. mcp_proxy_adapter/examples/basic_server/README.md +0 -60
  164. mcp_proxy_adapter/examples/basic_server/__init__.py +0 -7
  165. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +0 -39
  166. mcp_proxy_adapter/examples/basic_server/config.json +0 -70
  167. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +0 -54
  168. mcp_proxy_adapter/examples/basic_server/config_http.json +0 -70
  169. mcp_proxy_adapter/examples/basic_server/config_http_only.json +0 -52
  170. mcp_proxy_adapter/examples/basic_server/config_https.json +0 -58
  171. mcp_proxy_adapter/examples/basic_server/config_mtls.json +0 -58
  172. mcp_proxy_adapter/examples/basic_server/config_ssl.json +0 -46
  173. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +0 -238
  174. mcp_proxy_adapter/examples/basic_server/server.py +0 -114
  175. mcp_proxy_adapter/examples/custom_commands/README.md +0 -127
  176. mcp_proxy_adapter/examples/custom_commands/__init__.py +0 -27
  177. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +0 -566
  178. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +0 -6
  179. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +0 -103
  180. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +0 -111
  181. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +0 -105
  182. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +0 -129
  183. mcp_proxy_adapter/examples/custom_commands/config.json +0 -118
  184. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +0 -46
  185. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +0 -46
  186. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +0 -33
  187. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +0 -46
  188. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +0 -33
  189. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +0 -33
  190. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +0 -169
  191. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +0 -215
  192. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +0 -76
  193. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +0 -96
  194. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +0 -241
  195. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +0 -135
  196. mcp_proxy_adapter/examples/custom_commands/echo_command.py +0 -122
  197. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +0 -1
  198. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +0 -629
  199. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +0 -103
  200. mcp_proxy_adapter/examples/custom_commands/hooks.py +0 -230
  201. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +0 -123
  202. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +0 -129
  203. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +0 -103
  204. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +0 -278
  205. mcp_proxy_adapter/examples/custom_commands/server.py +0 -252
  206. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +0 -75
  207. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +0 -299
  208. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +0 -278
  209. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +0 -176
  210. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +0 -27
  211. mcp_proxy_adapter/examples/custom_commands/test_registry.py +0 -23
  212. mcp_proxy_adapter/examples/custom_commands/test_simple.py +0 -19
  213. mcp_proxy_adapter/examples/custom_project_example/README.md +0 -103
  214. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +0 -103
  215. mcp_proxy_adapter/examples/deployment/README.md +0 -49
  216. mcp_proxy_adapter/examples/deployment/__init__.py +0 -7
  217. mcp_proxy_adapter/examples/deployment/config.development.json +0 -8
  218. mcp_proxy_adapter/examples/deployment/config.json +0 -29
  219. mcp_proxy_adapter/examples/deployment/config.production.json +0 -12
  220. mcp_proxy_adapter/examples/deployment/config.staging.json +0 -11
  221. mcp_proxy_adapter/examples/deployment/docker-compose.yml +0 -31
  222. mcp_proxy_adapter/examples/deployment/run.sh +0 -43
  223. mcp_proxy_adapter/examples/deployment/run_docker.sh +0 -84
  224. mcp_proxy_adapter/examples/simple_custom_commands/README.md +0 -149
  225. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +0 -149
  226. mcp_proxy_adapter/schemas/base_schema.json +0 -114
  227. mcp_proxy_adapter/schemas/openapi_schema.json +0 -314
  228. mcp_proxy_adapter/schemas/roles_schema.json +0 -162
  229. mcp_proxy_adapter/tests/__init__.py +0 -0
  230. mcp_proxy_adapter/tests/api/__init__.py +0 -3
  231. mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +0 -115
  232. mcp_proxy_adapter/tests/api/test_custom_openapi.py +0 -617
  233. mcp_proxy_adapter/tests/api/test_handlers.py +0 -522
  234. mcp_proxy_adapter/tests/api/test_middleware.py +0 -340
  235. mcp_proxy_adapter/tests/api/test_schemas.py +0 -546
  236. mcp_proxy_adapter/tests/api/test_tool_integration.py +0 -531
  237. mcp_proxy_adapter/tests/commands/__init__.py +0 -3
  238. mcp_proxy_adapter/tests/commands/test_config_command.py +0 -211
  239. mcp_proxy_adapter/tests/commands/test_echo_command.py +0 -127
  240. mcp_proxy_adapter/tests/commands/test_help_command.py +0 -136
  241. mcp_proxy_adapter/tests/conftest.py +0 -131
  242. mcp_proxy_adapter/tests/functional/__init__.py +0 -3
  243. mcp_proxy_adapter/tests/functional/test_api.py +0 -253
  244. mcp_proxy_adapter/tests/integration/__init__.py +0 -3
  245. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +0 -129
  246. mcp_proxy_adapter/tests/integration/test_integration.py +0 -255
  247. mcp_proxy_adapter/tests/performance/__init__.py +0 -3
  248. mcp_proxy_adapter/tests/performance/test_performance.py +0 -189
  249. mcp_proxy_adapter/tests/stubs/__init__.py +0 -10
  250. mcp_proxy_adapter/tests/stubs/echo_command.py +0 -104
  251. mcp_proxy_adapter/tests/test_api_endpoints.py +0 -271
  252. mcp_proxy_adapter/tests/test_api_handlers.py +0 -289
  253. mcp_proxy_adapter/tests/test_base_command.py +0 -123
  254. mcp_proxy_adapter/tests/test_batch_requests.py +0 -117
  255. mcp_proxy_adapter/tests/test_command_registry.py +0 -281
  256. mcp_proxy_adapter/tests/test_config.py +0 -127
  257. mcp_proxy_adapter/tests/test_utils.py +0 -65
  258. mcp_proxy_adapter/tests/unit/__init__.py +0 -3
  259. mcp_proxy_adapter/tests/unit/test_base_command.py +0 -436
  260. mcp_proxy_adapter/tests/unit/test_config.py +0 -270
  261. mcp_proxy_adapter-6.0.0.dist-info/METADATA +0 -201
  262. mcp_proxy_adapter-6.0.0.dist-info/RECORD +0 -179
  263. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/WHEEL +0 -0
  264. {mcp_proxy_adapter-6.0.0.dist-info → mcp_proxy_adapter-6.1.1.dist-info}/top_level.txt +0 -0
@@ -13,9 +13,10 @@ from fastapi import FastAPI
13
13
  from mcp_proxy_adapter.core.logging import logger
14
14
  from mcp_proxy_adapter.core.security_factory import SecurityFactory
15
15
  from .base import BaseMiddleware
16
- from .security import SecurityMiddleware
16
+ from .unified_security import UnifiedSecurityMiddleware
17
17
  from .error_handling import ErrorHandlingMiddleware
18
18
  from .logging import LoggingMiddleware
19
+ from .user_info_middleware import UserInfoMiddleware
19
20
 
20
21
 
21
22
  class MiddlewareFactory:
@@ -40,12 +41,12 @@ class MiddlewareFactory:
40
41
 
41
42
  logger.info("Middleware factory initialized")
42
43
 
43
- def create_security_middleware(self) -> Optional[SecurityMiddleware]:
44
+ def create_security_middleware(self) -> Optional[UnifiedSecurityMiddleware]:
44
45
  """
45
- Create security middleware.
46
+ Create unified security middleware.
46
47
 
47
48
  Returns:
48
- SecurityMiddleware instance or None if creation failed
49
+ UnifiedSecurityMiddleware instance or None if creation failed
49
50
  """
50
51
  try:
51
52
  security_config = self.config.get("security", {})
@@ -54,14 +55,14 @@ class MiddlewareFactory:
54
55
  logger.info("Security middleware disabled by configuration")
55
56
  return None
56
57
 
57
- middleware = SecurityMiddleware(self.app, self.config)
58
+ middleware = UnifiedSecurityMiddleware(self.app, self.config)
58
59
  self.middleware_stack.append(middleware)
59
60
 
60
- logger.info("Security middleware created successfully")
61
+ logger.info("Unified security middleware created successfully")
61
62
  return middleware
62
63
 
63
64
  except Exception as e:
64
- logger.error(f"Failed to create security middleware: {e}")
65
+ logger.error(f"Failed to create unified security middleware: {e}")
65
66
  return None
66
67
 
67
68
  def create_error_handling_middleware(self) -> Optional[ErrorHandlingMiddleware]:
@@ -106,6 +107,24 @@ class MiddlewareFactory:
106
107
  logger.error(f"Failed to create logging middleware: {e}")
107
108
  return None
108
109
 
110
+ def create_user_info_middleware(self) -> Optional[UserInfoMiddleware]:
111
+ """
112
+ Create user info middleware.
113
+
114
+ Returns:
115
+ UserInfoMiddleware instance or None if creation failed
116
+ """
117
+ try:
118
+ middleware = UserInfoMiddleware(self.app, self.config)
119
+ self.middleware_stack.append(middleware)
120
+
121
+ logger.info("User info middleware created successfully")
122
+ return middleware
123
+
124
+ except Exception as e:
125
+ logger.error(f"Failed to create user info middleware: {e}")
126
+ return None
127
+
109
128
 
110
129
 
111
130
  def create_all_middleware(self) -> List[BaseMiddleware]:
@@ -132,6 +151,11 @@ class MiddlewareFactory:
132
151
  if logging_middleware:
133
152
  middleware_list.append(logging_middleware)
134
153
 
154
+ # Create user info middleware
155
+ user_info_middleware = self.create_user_info_middleware()
156
+ if user_info_middleware:
157
+ middleware_list.append(user_info_middleware)
158
+
135
159
  logger.info(f"Created {len(middleware_list)} middleware components")
136
160
  return middleware_list
137
161
 
@@ -152,14 +176,14 @@ class MiddlewareFactory:
152
176
  return middleware
153
177
  return None
154
178
 
155
- def get_security_middleware(self) -> Optional[SecurityMiddleware]:
179
+ def get_security_middleware(self) -> Optional[UnifiedSecurityMiddleware]:
156
180
  """
157
- Get security middleware instance.
181
+ Get unified security middleware instance.
158
182
 
159
183
  Returns:
160
- SecurityMiddleware instance or None if not found
184
+ UnifiedSecurityMiddleware instance or None if not found
161
185
  """
162
- return self.get_middleware_by_type(SecurityMiddleware)
186
+ return self.get_middleware_by_type(UnifiedSecurityMiddleware)
163
187
 
164
188
  def validate_middleware_config(self) -> bool:
165
189
  """
@@ -213,7 +237,7 @@ class MiddlewareFactory:
213
237
  middleware_type = type(middleware).__name__
214
238
  info["middleware_types"].append(middleware_type)
215
239
 
216
- if isinstance(middleware, SecurityMiddleware):
240
+ if isinstance(middleware, UnifiedSecurityMiddleware):
217
241
  info["security_enabled"] = True
218
242
 
219
243
  return info
@@ -4,12 +4,12 @@ Protocol middleware module.
4
4
  This module provides middleware for validating protocol access based on configuration.
5
5
  """
6
6
 
7
- from typing import Callable
7
+ from typing import Callable, Dict, Any, Optional
8
8
  from fastapi import Request, Response
9
9
  from starlette.middleware.base import BaseHTTPMiddleware
10
10
  from starlette.responses import JSONResponse
11
11
 
12
- from mcp_proxy_adapter.core.protocol_manager import protocol_manager
12
+ from mcp_proxy_adapter.core.protocol_manager import get_protocol_manager
13
13
  from mcp_proxy_adapter.core.logging import logger
14
14
 
15
15
 
@@ -21,16 +21,29 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
21
21
  based on the protocol configuration.
22
22
  """
23
23
 
24
- def __init__(self, app, protocol_manager_instance=None):
24
+ def __init__(self, app, app_config: Optional[Dict[str, Any]] = None):
25
25
  """
26
26
  Initialize protocol middleware.
27
27
 
28
28
  Args:
29
29
  app: FastAPI application
30
- protocol_manager_instance: Protocol manager instance (optional)
30
+ app_config: Application configuration dictionary (optional)
31
31
  """
32
32
  super().__init__(app)
33
- self.protocol_manager = protocol_manager_instance or protocol_manager
33
+ self.app_config = app_config
34
+ # Get protocol manager with current configuration
35
+ self.protocol_manager = get_protocol_manager(app_config)
36
+
37
+ def update_config(self, new_config: Dict[str, Any]):
38
+ """
39
+ Update configuration and reload protocol manager.
40
+
41
+ Args:
42
+ new_config: New configuration dictionary
43
+ """
44
+ self.app_config = new_config
45
+ self.protocol_manager = get_protocol_manager(new_config)
46
+ logger.info("Protocol middleware configuration updated")
34
47
 
35
48
  async def dispatch(self, request: Request, call_next: Callable) -> Response:
36
49
  """
@@ -116,20 +129,26 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
116
129
  return "http"
117
130
 
118
131
 
119
- def setup_protocol_middleware(app, protocol_manager_instance=None):
132
+ def setup_protocol_middleware(app, app_config: Optional[Dict[str, Any]] = None):
120
133
  """
121
134
  Setup protocol middleware for FastAPI application.
122
135
 
123
136
  Args:
124
137
  app: FastAPI application
125
- protocol_manager_instance: Protocol manager instance (optional)
138
+ app_config: Application configuration dictionary (optional)
126
139
  """
127
- if protocol_manager_instance is None:
128
- protocol_manager_instance = protocol_manager
140
+ # Check if protocol management is enabled
141
+ if app_config is None:
142
+ from mcp_proxy_adapter.config import config
143
+ app_config = config.get_all()
144
+
145
+ protocols_config = app_config.get("protocols", {})
146
+ enabled = protocols_config.get("enabled", True)
129
147
 
130
- # Only add middleware if protocol management is enabled
131
- if protocol_manager_instance.enabled:
132
- app.add_middleware(ProtocolMiddleware, protocol_manager_instance=protocol_manager_instance)
148
+ if enabled:
149
+ # Create protocol middleware with current configuration
150
+ middleware = ProtocolMiddleware(app, app_config)
151
+ app.add_middleware(ProtocolMiddleware, app_config=app_config)
133
152
  logger.info("Protocol middleware added to application")
134
153
  else:
135
- logger.debug("Protocol management is disabled, skipping protocol middleware")
154
+ logger.info("Protocol management is disabled, skipping protocol middleware")
@@ -0,0 +1,160 @@
1
+ """
2
+ Unified Security Middleware - Direct Framework Integration
3
+
4
+ This middleware now directly uses mcp_security_framework components
5
+ instead of custom implementations.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import time
12
+ import logging
13
+ from typing import Dict, Any, Optional, Callable, Awaitable
14
+ from fastapi import Request, Response
15
+ from starlette.middleware.base import BaseHTTPMiddleware
16
+
17
+ # Direct import from framework
18
+ try:
19
+ from mcp_security_framework.middleware.fastapi_middleware import FastAPISecurityMiddleware
20
+ from mcp_security_framework import SecurityManager
21
+ from mcp_security_framework.schemas.config import SecurityConfig
22
+ SECURITY_FRAMEWORK_AVAILABLE = True
23
+ except ImportError:
24
+ SECURITY_FRAMEWORK_AVAILABLE = False
25
+ FastAPISecurityMiddleware = None
26
+ SecurityManager = None
27
+ SecurityConfig = None
28
+
29
+ from mcp_proxy_adapter.core.logging import logger
30
+ from mcp_proxy_adapter.core.security_integration import create_security_integration
31
+
32
+
33
+ class SecurityValidationError(Exception):
34
+ """Security validation error."""
35
+
36
+ def __init__(self, message: str, error_code: int):
37
+ self.message = message
38
+ self.error_code = error_code
39
+ super().__init__(self.message)
40
+
41
+
42
+ class UnifiedSecurityMiddleware(BaseHTTPMiddleware):
43
+ """
44
+ Unified security middleware using mcp_security_framework.
45
+
46
+ This middleware now directly uses the security framework's FastAPI middleware
47
+ and components instead of custom implementations.
48
+ """
49
+
50
+ def __init__(self, app, config: Dict[str, Any]):
51
+ """
52
+ Initialize unified security middleware.
53
+
54
+ Args:
55
+ app: FastAPI application
56
+ config: mcp_proxy_adapter configuration dictionary
57
+ """
58
+ super().__init__(app)
59
+ self.config = config
60
+
61
+ # Create security integration
62
+ try:
63
+ self.security_integration = create_security_integration(config)
64
+ # Use framework's FastAPI middleware
65
+ self.framework_middleware = self.security_integration.create_fastapi_middleware(app)
66
+ logger.info("Using mcp_security_framework FastAPI middleware")
67
+ except Exception as e:
68
+ logger.error(f"Security framework integration failed: {e}")
69
+ # Instead of raising error, log warning and continue without security
70
+ logger.warning("Continuing without security framework - some security features will be disabled")
71
+ self.security_integration = None
72
+ self.framework_middleware = None
73
+
74
+ logger.info("Unified security middleware initialized")
75
+
76
+ async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
77
+ """
78
+ Process request using framework middleware.
79
+
80
+ Args:
81
+ request: Request object
82
+ call_next: Next handler
83
+
84
+ Returns:
85
+ Response object
86
+ """
87
+ try:
88
+ # Use framework middleware if available
89
+ if self.framework_middleware is not None:
90
+ return await self.framework_middleware.dispatch(request, call_next)
91
+ else:
92
+ # Fallback: continue without security middleware
93
+ logger.debug("Security framework not available, continuing without security checks")
94
+ return await call_next(request)
95
+
96
+ except SecurityValidationError as e:
97
+ # Handle security validation errors
98
+ return await self._handle_security_error(request, e)
99
+ except Exception as e:
100
+ # Handle other errors
101
+ logger.error(f"Unexpected error in unified security middleware: {e}")
102
+ return await self._handle_general_error(request, e)
103
+
104
+
105
+
106
+ async def _handle_security_error(self, request: Request, error: SecurityValidationError) -> Response:
107
+ """
108
+ Handle security validation errors.
109
+
110
+ Args:
111
+ request: Request object
112
+ error: Security validation error
113
+
114
+ Returns:
115
+ Error response
116
+ """
117
+ from fastapi.responses import JSONResponse
118
+
119
+ error_response = {
120
+ "error": {
121
+ "code": error.error_code,
122
+ "message": error.message,
123
+ "type": "security_validation_error"
124
+ }
125
+ }
126
+
127
+ logger.warning(f"Security validation failed: {error.message}")
128
+
129
+ return JSONResponse(
130
+ status_code=error.error_code,
131
+ content=error_response
132
+ )
133
+
134
+ async def _handle_general_error(self, request: Request, error: Exception) -> Response:
135
+ """
136
+ Handle general errors.
137
+
138
+ Args:
139
+ request: Request object
140
+ error: General error
141
+
142
+ Returns:
143
+ Error response
144
+ """
145
+ from fastapi.responses import JSONResponse
146
+
147
+ error_response = {
148
+ "error": {
149
+ "code": 500,
150
+ "message": "Internal server error",
151
+ "type": "general_error"
152
+ }
153
+ }
154
+
155
+ logger.error(f"General error in security middleware: {error}")
156
+
157
+ return JSONResponse(
158
+ status_code=500,
159
+ content=error_response
160
+ )
@@ -0,0 +1,83 @@
1
+ """
2
+ User Info Middleware
3
+
4
+ This middleware extracts user information from authentication headers
5
+ and sets it in request.state for use by commands.
6
+
7
+ Author: Vasiliy Zdanovskiy
8
+ email: vasilyvz@gmail.com
9
+ """
10
+
11
+ import logging
12
+ from typing import Dict, Any, Optional, Callable, Awaitable
13
+ from fastapi import Request, Response
14
+ from starlette.middleware.base import BaseHTTPMiddleware
15
+
16
+ from mcp_proxy_adapter.core.logging import logger
17
+
18
+
19
+ class UserInfoMiddleware(BaseHTTPMiddleware):
20
+ """
21
+ Middleware for setting user information in request.state.
22
+
23
+ This middleware extracts user information from authentication headers
24
+ and sets it in request.state for use by commands.
25
+ """
26
+
27
+ def __init__(self, app, config: Dict[str, Any]):
28
+ """
29
+ Initialize user info middleware.
30
+
31
+ Args:
32
+ app: FastAPI application
33
+ config: Configuration dictionary
34
+ """
35
+ super().__init__(app)
36
+ self.config = config
37
+
38
+ # Get API keys configuration
39
+ security_config = config.get("security", {})
40
+ auth_config = security_config.get("auth", {})
41
+ self.api_keys = auth_config.get("api_keys", {})
42
+
43
+ logger.info("User info middleware initialized")
44
+
45
+ async def dispatch(self, request: Request, call_next: Callable[[Request], Awaitable[Response]]) -> Response:
46
+ """
47
+ Process request and set user info in request.state.
48
+
49
+ Args:
50
+ request: Request object
51
+ call_next: Next handler
52
+
53
+ Returns:
54
+ Response object
55
+ """
56
+ # Extract API key from headers
57
+ api_key = request.headers.get("X-API-Key")
58
+
59
+ if api_key and api_key in self.api_keys:
60
+ # Get user info from API key configuration
61
+ user_config = self.api_keys[api_key]
62
+
63
+ # Set user info in request.state
64
+ request.state.user = {
65
+ "id": api_key,
66
+ "role": user_config.get("roles", ["guest"])[0] if user_config.get("roles") else "guest",
67
+ "roles": user_config.get("roles", ["guest"]),
68
+ "permissions": user_config.get("permissions", ["read"])
69
+ }
70
+
71
+ logger.debug(f"Set user info for {api_key}: {request.state.user}")
72
+ else:
73
+ # Set default guest user info
74
+ request.state.user = {
75
+ "id": None,
76
+ "role": "guest",
77
+ "roles": ["guest"],
78
+ "permissions": ["read"]
79
+ }
80
+
81
+ logger.debug("Set default guest user info")
82
+
83
+ return await call_next(request)
@@ -12,6 +12,9 @@ from mcp_proxy_adapter.commands.certificate_management_command import Certificat
12
12
  from mcp_proxy_adapter.commands.key_management_command import KeyManagementCommand
13
13
  from mcp_proxy_adapter.commands.cert_monitor_command import CertMonitorCommand
14
14
  from mcp_proxy_adapter.commands.transport_management_command import TransportManagementCommand
15
+ from mcp_proxy_adapter.commands.role_test_command import RoleTestCommand
16
+ from mcp_proxy_adapter.commands.echo_command import EchoCommand
17
+ from mcp_proxy_adapter.commands.proxy_registration_command import ProxyRegistrationCommand
15
18
 
16
19
  __all__ = [
17
20
  "Command",
@@ -27,5 +30,8 @@ __all__ = [
27
30
  "CertificateManagementCommand",
28
31
  "KeyManagementCommand",
29
32
  "CertMonitorCommand",
30
- "TransportManagementCommand"
33
+ "TransportManagementCommand",
34
+ "RoleTestCommand",
35
+ "EchoCommand",
36
+ "ProxyRegistrationCommand"
31
37
  ]
@@ -48,7 +48,7 @@ class Command(ABC):
48
48
  Execute command with the specified parameters.
49
49
 
50
50
  Args:
51
- **kwargs: Command parameters.
51
+ **kwargs: Command parameters including optional 'context' parameter.
52
52
 
53
53
  Returns:
54
54
  Command result.
@@ -153,11 +153,14 @@ class Command(ABC):
153
153
  Runs the command with the specified arguments.
154
154
 
155
155
  Args:
156
- **kwargs: Command arguments.
156
+ **kwargs: Command arguments including optional 'context' parameter.
157
157
 
158
158
  Returns:
159
159
  Command result.
160
160
  """
161
+ # Extract context from kwargs
162
+ context = kwargs.pop('context', {}) if 'context' in kwargs else {}
163
+
161
164
  try:
162
165
  logger.debug(f"Running command {cls.__name__} with params: {kwargs}")
163
166
 
@@ -185,8 +188,8 @@ class Command(ABC):
185
188
  command = command_class()
186
189
  validated_params = command.validate_params(kwargs)
187
190
 
188
- # Execute command with validated parameters
189
- result = await command.execute(**validated_params)
191
+ # Execute command with validated parameters and context
192
+ result = await command.execute(**validated_params, context=context)
190
193
 
191
194
  logger.debug(f"Command {cls.__name__} executed successfully")
192
195
  return result
@@ -17,6 +17,8 @@ from mcp_proxy_adapter.commands.unload_command import UnloadCommand
17
17
  from mcp_proxy_adapter.commands.plugins_command import PluginsCommand
18
18
  from mcp_proxy_adapter.commands.transport_management_command import TransportManagementCommand
19
19
  from mcp_proxy_adapter.commands.proxy_registration_command import ProxyRegistrationCommand
20
+ from mcp_proxy_adapter.commands.echo_command import EchoCommand
21
+ from mcp_proxy_adapter.commands.role_test_command import RoleTestCommand
20
22
  from mcp_proxy_adapter.core.logging import logger
21
23
 
22
24
 
@@ -39,7 +41,9 @@ def register_builtin_commands() -> int:
39
41
  UnloadCommand,
40
42
  PluginsCommand,
41
43
  TransportManagementCommand,
42
- ProxyRegistrationCommand
44
+ ProxyRegistrationCommand,
45
+ EchoCommand,
46
+ RoleTestCommand
43
47
  ]
44
48
 
45
49
  registered_count = 0
@@ -85,5 +89,7 @@ def get_builtin_commands_list() -> list:
85
89
  UnloadCommand,
86
90
  PluginsCommand,
87
91
  TransportManagementCommand,
88
- ProxyRegistrationCommand
92
+ ProxyRegistrationCommand,
93
+ EchoCommand,
94
+ RoleTestCommand
89
95
  ]
@@ -660,6 +660,14 @@ class CommandRegistry:
660
660
  except Exception as e:
661
661
  logger.error(f"❌ Failed to initialize logging: {e}")
662
662
 
663
+ # Step 2.5: Reload protocol manager configuration
664
+ try:
665
+ from mcp_proxy_adapter.core.protocol_manager import protocol_manager
666
+ protocol_manager.reload_config()
667
+ logger.info("✅ Protocol manager configuration reloaded")
668
+ except Exception as e:
669
+ logger.error(f"❌ Failed to reload protocol manager: {e}")
670
+
663
671
  # Step 3: Clear all commands (always clear for consistency)
664
672
  self.clear()
665
673
 
@@ -0,0 +1,81 @@
1
+ """
2
+ Author: Vasiliy Zdanovskiy
3
+ email: vasilyvz@gmail.com
4
+
5
+ Echo command for testing purposes.
6
+ """
7
+
8
+ import asyncio
9
+ from typing import Any, Dict, Optional
10
+
11
+ from mcp_proxy_adapter.commands.base import Command
12
+ from mcp_proxy_adapter.commands.result import SuccessResult
13
+
14
+
15
+ class EchoCommandResult(SuccessResult):
16
+ """Result for echo command."""
17
+
18
+ def __init__(self, message: str, timestamp: Optional[str] = None):
19
+ data = {"message": message}
20
+ if timestamp:
21
+ data["timestamp"] = timestamp
22
+ super().__init__(data=data, message=message)
23
+
24
+ @classmethod
25
+ def get_schema(cls) -> Dict[str, Any]:
26
+ """Get JSON schema for result."""
27
+ return {
28
+ "type": "object",
29
+ "properties": {
30
+ "success": {"type": "boolean"},
31
+ "data": {
32
+ "type": "object",
33
+ "properties": {
34
+ "message": {"type": "string"},
35
+ "timestamp": {"type": "string", "nullable": True}
36
+ }
37
+ },
38
+ "message": {"type": "string"}
39
+ },
40
+ "required": ["success", "data"]
41
+ }
42
+
43
+
44
+ class EchoCommand(Command):
45
+ """Echo command for testing purposes."""
46
+
47
+ name = "echo"
48
+ version = "1.0.0"
49
+ descr = "Echo command for testing"
50
+ category = "testing"
51
+ author = "Vasiliy Zdanovskiy"
52
+ email = "vasilyvz@gmail.com"
53
+ result_class = EchoCommandResult
54
+
55
+ async def execute(self, **kwargs) -> EchoCommandResult:
56
+ """Execute echo command."""
57
+ message = kwargs.get("message", "Hello, World!")
58
+ timestamp = kwargs.get("timestamp")
59
+
60
+ # Simulate some processing time
61
+ await asyncio.sleep(0.001)
62
+
63
+ return EchoCommandResult(message=message, timestamp=timestamp)
64
+
65
+ def get_schema(self) -> Dict[str, Any]:
66
+ """Get command schema."""
67
+ return {
68
+ "type": "object",
69
+ "properties": {
70
+ "message": {
71
+ "type": "string",
72
+ "description": "Message to echo",
73
+ "default": "Hello, World!"
74
+ },
75
+ "timestamp": {
76
+ "type": "string",
77
+ "description": "Optional timestamp",
78
+ "nullable": True
79
+ }
80
+ }
81
+ }