mcp-proxy-adapter 6.9.27__py3-none-any.whl → 6.9.29__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.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +10 -0
- mcp_proxy_adapter/__main__.py +8 -21
- mcp_proxy_adapter/api/app.py +10 -913
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +243 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_manager.py +166 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +78 -199
- mcp_proxy_adapter/api/middleware/__init__.py +1 -44
- mcp_proxy_adapter/api/middleware/base.py +0 -42
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +0 -85
- mcp_proxy_adapter/api/middleware/error_handling.py +1 -127
- mcp_proxy_adapter/api/middleware/factory.py +0 -94
- mcp_proxy_adapter/api/middleware/logging.py +0 -112
- mcp_proxy_adapter/api/middleware/performance.py +0 -35
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +2 -98
- mcp_proxy_adapter/api/middleware/transport_middleware.py +0 -37
- mcp_proxy_adapter/api/middleware/unified_security.py +10 -10
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +0 -118
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +0 -61
- mcp_proxy_adapter/api/tool_integration.py +0 -117
- mcp_proxy_adapter/api/tools.py +0 -46
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +21 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +36 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +128 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +324 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client.py +406 -0
- mcp_proxy_adapter/client/proxy.py +45 -0
- mcp_proxy_adapter/commands/__init__.py +44 -28
- mcp_proxy_adapter/commands/auth_validation_command.py +7 -344
- mcp_proxy_adapter/commands/base.py +19 -43
- mcp_proxy_adapter/commands/builtin_commands.py +0 -75
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +58 -928
- mcp_proxy_adapter/commands/cert_monitor_command.py +0 -88
- mcp_proxy_adapter/commands/certificate_management_command.py +0 -45
- mcp_proxy_adapter/commands/command_registry.py +172 -904
- mcp_proxy_adapter/commands/config_command.py +0 -28
- mcp_proxy_adapter/commands/dependency_container.py +1 -70
- mcp_proxy_adapter/commands/dependency_manager.py +0 -128
- mcp_proxy_adapter/commands/echo_command.py +0 -34
- mcp_proxy_adapter/commands/health_command.py +0 -3
- mcp_proxy_adapter/commands/help_command.py +0 -159
- mcp_proxy_adapter/commands/hooks.py +0 -137
- mcp_proxy_adapter/commands/key_management_command.py +0 -25
- mcp_proxy_adapter/commands/load_command.py +7 -78
- mcp_proxy_adapter/commands/plugins_command.py +0 -16
- mcp_proxy_adapter/commands/protocol_management_command.py +0 -28
- mcp_proxy_adapter/commands/proxy_registration_command.py +0 -88
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +0 -43
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +0 -80
- mcp_proxy_adapter/commands/result.py +25 -77
- mcp_proxy_adapter/commands/role_test_command.py +0 -44
- mcp_proxy_adapter/commands/roles_management_command.py +0 -199
- mcp_proxy_adapter/commands/security_command.py +0 -30
- mcp_proxy_adapter/commands/settings_command.py +0 -68
- mcp_proxy_adapter/commands/ssl_setup_command.py +0 -42
- mcp_proxy_adapter/commands/token_management_command.py +0 -1
- mcp_proxy_adapter/commands/transport_management_command.py +0 -20
- mcp_proxy_adapter/commands/unload_command.py +0 -71
- mcp_proxy_adapter/config.py +15 -626
- mcp_proxy_adapter/core/__init__.py +5 -39
- mcp_proxy_adapter/core/app_factory.py +14 -36
- mcp_proxy_adapter/core/app_runner.py +0 -27
- mcp_proxy_adapter/core/auth_validator.py +1 -93
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +371 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +183 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +110 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +70 -0
- mcp_proxy_adapter/core/certificate_utils.py +64 -903
- mcp_proxy_adapter/core/client.py +0 -6
- mcp_proxy_adapter/core/client_manager.py +0 -19
- mcp_proxy_adapter/core/client_security.py +0 -2
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +195 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +112 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +50 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +96 -0
- mcp_proxy_adapter/core/config_converter.py +0 -186
- mcp_proxy_adapter/core/config_validator.py +96 -1238
- mcp_proxy_adapter/core/errors.py +7 -42
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +2 -22
- mcp_proxy_adapter/core/mtls_asgi.py +0 -20
- mcp_proxy_adapter/core/mtls_asgi_app.py +0 -12
- mcp_proxy_adapter/core/mtls_proxy.py +0 -80
- mcp_proxy_adapter/core/mtls_server.py +3 -173
- mcp_proxy_adapter/core/protocol_manager.py +1 -191
- mcp_proxy_adapter/core/proxy/__init__.py +22 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +27 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +137 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +60 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +0 -1
- mcp_proxy_adapter/core/proxy_registration.py +36 -912
- mcp_proxy_adapter/core/role_utils.py +0 -308
- mcp_proxy_adapter/core/security_adapter.py +1 -36
- mcp_proxy_adapter/core/security_factory.py +1 -150
- mcp_proxy_adapter/core/security_integration.py +0 -33
- mcp_proxy_adapter/core/server_adapter.py +1 -40
- mcp_proxy_adapter/core/server_engine.py +2 -173
- mcp_proxy_adapter/core/settings.py +0 -127
- mcp_proxy_adapter/core/signal_handler.py +0 -65
- mcp_proxy_adapter/core/ssl_utils.py +19 -137
- mcp_proxy_adapter/core/transport_manager.py +0 -151
- mcp_proxy_adapter/core/unified_config_adapter.py +1 -193
- mcp_proxy_adapter/core/utils.py +1 -182
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +211 -0
- mcp_proxy_adapter/core/validation/file_validator.py +73 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +191 -0
- mcp_proxy_adapter/core/validation/security_validator.py +58 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +33 -652
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +0 -23
- mcp_proxy_adapter/examples/check_config.py +0 -2
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/config_builder.py +13 -2
- mcp_proxy_adapter/examples/config_cli.py +0 -1
- mcp_proxy_adapter/examples/create_test_configs.py +0 -46
- mcp_proxy_adapter/examples/debug_request_state.py +0 -1
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +0 -47
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +0 -45
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +0 -12
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +0 -7
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +0 -2
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +0 -59
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +0 -54
- mcp_proxy_adapter/examples/full_application/main.py +186 -150
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +0 -107
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +0 -24
- mcp_proxy_adapter/examples/full_application/test_server.py +0 -58
- mcp_proxy_adapter/examples/generate_config.py +65 -11
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +0 -2
- mcp_proxy_adapter/examples/run_full_test_suite.py +0 -29
- mcp_proxy_adapter/examples/run_proxy_server.py +31 -71
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +0 -27
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +24 -1075
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +133 -1425
- mcp_proxy_adapter/examples/test_config.py +0 -3
- mcp_proxy_adapter/examples/test_config_builder.py +25 -405
- mcp_proxy_adapter/examples/test_examples.py +0 -1
- mcp_proxy_adapter/examples/test_framework_complete.py +0 -2
- mcp_proxy_adapter/examples/test_mcp_server.py +0 -1
- mcp_proxy_adapter/examples/test_protocol_examples.py +0 -1
- mcp_proxy_adapter/examples/universal_client.py +0 -6
- mcp_proxy_adapter/examples/update_config_certificates.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +0 -1
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +0 -187
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +70 -62
- mcp_proxy_adapter/openapi.py +0 -22
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.9.29.dist-info/RECORD +235 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/entry_points.txt +1 -1
- mcp_proxy_adapter-6.9.27.dist-info/RECORD +0 -149
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.9.27.dist-info → mcp_proxy_adapter-6.9.29.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ Middleware for error handling.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Optional, Any
|
|
7
7
|
|
|
8
8
|
from fastapi import Request, Response
|
|
9
9
|
from starlette.responses import JSONResponse
|
|
@@ -31,132 +31,6 @@ class ErrorHandlingMiddleware(BaseMiddleware):
|
|
|
31
31
|
"""
|
|
32
32
|
super().__init__(app)
|
|
33
33
|
|
|
34
|
-
async def dispatch(
|
|
35
|
-
self, request: Request, call_next: Callable[[Request], Awaitable[Response]]
|
|
36
|
-
) -> Response:
|
|
37
|
-
"""
|
|
38
|
-
Processes request and catches errors.
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
request: Request.
|
|
42
|
-
call_next: Next handler.
|
|
43
|
-
|
|
44
|
-
Returns:
|
|
45
|
-
Response.
|
|
46
|
-
"""
|
|
47
|
-
get_global_logger().debug(f"🔍 ErrorHandlingMiddleware.dispatch START - {request.method} {request.url.path}")
|
|
48
|
-
try:
|
|
49
|
-
# Call the next middleware or main handler
|
|
50
|
-
get_global_logger().debug(f"🔍 ErrorHandlingMiddleware - About to call next handler")
|
|
51
|
-
response = await call_next(request)
|
|
52
|
-
get_global_logger().debug(f"🔍 ErrorHandlingMiddleware - Next handler completed with status: {response.status_code}")
|
|
53
|
-
return response
|
|
54
|
-
|
|
55
|
-
except CommandError as e:
|
|
56
|
-
# Command error
|
|
57
|
-
request_id = getattr(request.state, "request_id", "unknown")
|
|
58
|
-
get_global_logger().debug(f"[{request_id}] Command error: {str(e)}")
|
|
59
|
-
|
|
60
|
-
# Проверяем, является ли запрос JSON-RPC
|
|
61
|
-
is_jsonrpc = self._is_json_rpc_request(request)
|
|
62
|
-
|
|
63
|
-
# Get JSON-RPC request ID if available
|
|
64
|
-
request_id_jsonrpc = await self._get_json_rpc_id(request)
|
|
65
|
-
|
|
66
|
-
# If request was JSON-RPC
|
|
67
|
-
if is_jsonrpc:
|
|
68
|
-
return JSONResponse(
|
|
69
|
-
status_code=400,
|
|
70
|
-
content={
|
|
71
|
-
"jsonrpc": "2.0",
|
|
72
|
-
"error": {
|
|
73
|
-
"code": e.code,
|
|
74
|
-
"message": str(e),
|
|
75
|
-
"data": e.data if hasattr(e, "data") and e.data else None,
|
|
76
|
-
},
|
|
77
|
-
"id": request_id_jsonrpc,
|
|
78
|
-
},
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
# Regular API error
|
|
82
|
-
return JSONResponse(status_code=400, content=e.to_dict())
|
|
83
|
-
|
|
84
|
-
except ValidationError as e:
|
|
85
|
-
# Validation error
|
|
86
|
-
request_id = getattr(request.state, "request_id", "unknown")
|
|
87
|
-
get_global_logger().debug(f"[{request_id}] Validation error: {str(e)}")
|
|
88
|
-
|
|
89
|
-
# Get JSON-RPC request ID if available
|
|
90
|
-
request_id_jsonrpc = await self._get_json_rpc_id(request)
|
|
91
|
-
|
|
92
|
-
# If request was JSON-RPC
|
|
93
|
-
if self._is_json_rpc_request(request):
|
|
94
|
-
return JSONResponse(
|
|
95
|
-
status_code=400,
|
|
96
|
-
content={
|
|
97
|
-
"jsonrpc": "2.0",
|
|
98
|
-
"error": {
|
|
99
|
-
"code": -32602,
|
|
100
|
-
"message": "Invalid params",
|
|
101
|
-
"data": e.data if hasattr(e, "data") and e.data else None,
|
|
102
|
-
},
|
|
103
|
-
"id": request_id_jsonrpc,
|
|
104
|
-
},
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
# Regular API error
|
|
108
|
-
return JSONResponse(status_code=400, content=e.to_dict())
|
|
109
|
-
|
|
110
|
-
except MicroserviceError as e:
|
|
111
|
-
# Other microservice error
|
|
112
|
-
request_id = getattr(request.state, "request_id", "unknown")
|
|
113
|
-
get_global_logger().debug(f"[{request_id}] Microservice error: {str(e)}")
|
|
114
|
-
|
|
115
|
-
# Get JSON-RPC request ID if available
|
|
116
|
-
request_id_jsonrpc = await self._get_json_rpc_id(request)
|
|
117
|
-
|
|
118
|
-
# If request was JSON-RPC
|
|
119
|
-
if self._is_json_rpc_request(request):
|
|
120
|
-
return JSONResponse(
|
|
121
|
-
status_code=400,
|
|
122
|
-
content={
|
|
123
|
-
"jsonrpc": "2.0",
|
|
124
|
-
"error": {
|
|
125
|
-
"code": -32000,
|
|
126
|
-
"message": str(e),
|
|
127
|
-
"data": e.data if hasattr(e, "data") and e.data else None,
|
|
128
|
-
},
|
|
129
|
-
"id": request_id_jsonrpc,
|
|
130
|
-
},
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
# Regular API error
|
|
134
|
-
return JSONResponse(status_code=400, content=e.to_dict())
|
|
135
|
-
|
|
136
|
-
except Exception as e:
|
|
137
|
-
# Unexpected error
|
|
138
|
-
request_id = getattr(request.state, "request_id", "unknown")
|
|
139
|
-
get_global_logger().debug(f"[{request_id}] Unexpected error: {str(e)}")
|
|
140
|
-
|
|
141
|
-
# Get JSON-RPC request ID if available
|
|
142
|
-
request_id_jsonrpc = await self._get_json_rpc_id(request)
|
|
143
|
-
|
|
144
|
-
# If request was JSON-RPC
|
|
145
|
-
if self._is_json_rpc_request(request):
|
|
146
|
-
return JSONResponse(
|
|
147
|
-
status_code=500,
|
|
148
|
-
content={
|
|
149
|
-
"jsonrpc": "2.0",
|
|
150
|
-
"error": {"code": -32603, "message": "Internal error"},
|
|
151
|
-
"id": request_id_jsonrpc,
|
|
152
|
-
},
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
# Regular API error
|
|
156
|
-
return JSONResponse(
|
|
157
|
-
status_code=500,
|
|
158
|
-
content={"error": {"code": 500, "message": "Internal server error"}},
|
|
159
|
-
)
|
|
160
34
|
|
|
161
35
|
def _is_json_rpc_request(self, request: Request) -> bool:
|
|
162
36
|
"""
|
|
@@ -125,37 +125,6 @@ class MiddlewareFactory:
|
|
|
125
125
|
get_global_logger().error(f"Failed to create user info middleware: {e}")
|
|
126
126
|
return None
|
|
127
127
|
|
|
128
|
-
def create_all_middleware(self) -> List[BaseMiddleware]:
|
|
129
|
-
"""
|
|
130
|
-
Create all required middleware components.
|
|
131
|
-
|
|
132
|
-
Returns:
|
|
133
|
-
List of created middleware instances
|
|
134
|
-
"""
|
|
135
|
-
middleware_list = []
|
|
136
|
-
|
|
137
|
-
# Create security middleware (unified)
|
|
138
|
-
security_middleware = self.create_security_middleware()
|
|
139
|
-
if security_middleware:
|
|
140
|
-
middleware_list.append(security_middleware)
|
|
141
|
-
|
|
142
|
-
# Create error handling middleware
|
|
143
|
-
error_middleware = self.create_error_handling_middleware()
|
|
144
|
-
if error_middleware:
|
|
145
|
-
middleware_list.append(error_middleware)
|
|
146
|
-
|
|
147
|
-
# Create logging middleware
|
|
148
|
-
logging_middleware = self.create_logging_middleware()
|
|
149
|
-
if logging_middleware:
|
|
150
|
-
middleware_list.append(logging_middleware)
|
|
151
|
-
|
|
152
|
-
# Create user info middleware
|
|
153
|
-
user_info_middleware = self.create_user_info_middleware()
|
|
154
|
-
if user_info_middleware:
|
|
155
|
-
middleware_list.append(user_info_middleware)
|
|
156
|
-
|
|
157
|
-
get_global_logger().info(f"Created {len(middleware_list)} middleware components")
|
|
158
|
-
return middleware_list
|
|
159
128
|
|
|
160
129
|
def get_middleware_by_type(
|
|
161
130
|
self, middleware_type: Type[BaseMiddleware]
|
|
@@ -174,68 +143,5 @@ class MiddlewareFactory:
|
|
|
174
143
|
return middleware
|
|
175
144
|
return None
|
|
176
145
|
|
|
177
|
-
def get_security_middleware(self) -> Optional[UnifiedSecurityMiddleware]:
|
|
178
|
-
"""
|
|
179
|
-
Get unified security middleware instance.
|
|
180
|
-
|
|
181
|
-
Returns:
|
|
182
|
-
UnifiedSecurityMiddleware instance or None if not found
|
|
183
|
-
"""
|
|
184
|
-
return self.get_middleware_by_type(UnifiedSecurityMiddleware)
|
|
185
|
-
|
|
186
|
-
def validate_middleware_config(self) -> bool:
|
|
187
|
-
"""
|
|
188
|
-
Validate middleware configuration.
|
|
189
|
-
|
|
190
|
-
Returns:
|
|
191
|
-
True if configuration is valid, False otherwise
|
|
192
|
-
"""
|
|
193
|
-
try:
|
|
194
|
-
security_config = self.config.get("security", {})
|
|
195
|
-
|
|
196
|
-
# Validate security configuration
|
|
197
|
-
if not SecurityFactory.validate_config(self.config):
|
|
198
|
-
get_global_logger().error("Security configuration validation failed")
|
|
199
|
-
return False
|
|
200
|
-
|
|
201
|
-
# Validate middleware-specific configurations
|
|
202
|
-
if security_config.get("enabled", True):
|
|
203
|
-
# Check required fields for security middleware
|
|
204
|
-
auth_config = security_config.get("auth", {})
|
|
205
|
-
if not isinstance(auth_config, dict):
|
|
206
|
-
get_global_logger().error("Auth configuration must be a dictionary")
|
|
207
|
-
return False
|
|
208
|
-
|
|
209
|
-
ssl_config = security_config.get("ssl", {})
|
|
210
|
-
if not isinstance(ssl_config, dict):
|
|
211
|
-
get_global_logger().error("SSL configuration must be a dictionary")
|
|
212
|
-
return False
|
|
213
|
-
|
|
214
|
-
get_global_logger().info("Middleware configuration validation passed")
|
|
215
|
-
return True
|
|
216
|
-
|
|
217
|
-
except Exception as e:
|
|
218
|
-
get_global_logger().error(f"Middleware configuration validation failed: {e}")
|
|
219
|
-
return False
|
|
220
|
-
|
|
221
|
-
def get_middleware_info(self) -> Dict[str, Any]:
|
|
222
|
-
"""
|
|
223
|
-
Get information about created middleware.
|
|
224
|
-
|
|
225
|
-
Returns:
|
|
226
|
-
Dictionary with middleware information
|
|
227
|
-
"""
|
|
228
|
-
info = {
|
|
229
|
-
"total_middleware": len(self.middleware_stack),
|
|
230
|
-
"middleware_types": [],
|
|
231
|
-
"security_enabled": False,
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
for middleware in self.middleware_stack:
|
|
235
|
-
middleware_type = type(middleware).__name__
|
|
236
|
-
info["middleware_types"].append(middleware_type)
|
|
237
146
|
|
|
238
|
-
if isinstance(middleware, UnifiedSecurityMiddleware):
|
|
239
|
-
info["security_enabled"] = True
|
|
240
147
|
|
|
241
|
-
return info
|
|
@@ -29,115 +29,3 @@ class LoggingMiddleware(BaseMiddleware):
|
|
|
29
29
|
super().__init__(app)
|
|
30
30
|
self.config = config or {}
|
|
31
31
|
|
|
32
|
-
async def dispatch(
|
|
33
|
-
self, request: Request, call_next: Callable[[Request], Awaitable[Response]]
|
|
34
|
-
) -> Response:
|
|
35
|
-
"""
|
|
36
|
-
Processes request and logs information about it.
|
|
37
|
-
|
|
38
|
-
Args:
|
|
39
|
-
request: Request.
|
|
40
|
-
call_next: Next handler.
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
Response.
|
|
44
|
-
"""
|
|
45
|
-
get_global_logger().debug(f"🔍 LoggingMiddleware.dispatch START - {request.method} {request.url.path}")
|
|
46
|
-
|
|
47
|
-
# Generate unique ID for request
|
|
48
|
-
request_id = str(uuid.uuid4())
|
|
49
|
-
request.state.request_id = request_id
|
|
50
|
-
get_global_logger().debug(f"🔍 LoggingMiddleware - Generated request ID: {request_id}")
|
|
51
|
-
|
|
52
|
-
# Create context get_global_logger() for this request
|
|
53
|
-
req_logger = RequestLogger("mcp_proxy_adapter.api.middleware", request_id)
|
|
54
|
-
|
|
55
|
-
# Log request start
|
|
56
|
-
start_time = time.time()
|
|
57
|
-
|
|
58
|
-
# Request information
|
|
59
|
-
method = request.method
|
|
60
|
-
url = str(request.url)
|
|
61
|
-
client_host = request.client.host if request.client else "unknown"
|
|
62
|
-
|
|
63
|
-
# Check if this is an OpenAPI schema request (should be logged at DEBUG level)
|
|
64
|
-
is_openapi_request = "/openapi.json" in url
|
|
65
|
-
|
|
66
|
-
if is_openapi_request:
|
|
67
|
-
req_logger.debug(f"Request started: {method} {url} | Client: {client_host}")
|
|
68
|
-
else:
|
|
69
|
-
req_logger.info(f"Request started: {method} {url} | Client: {client_host}")
|
|
70
|
-
|
|
71
|
-
# Log request body if not GET or HEAD
|
|
72
|
-
if method not in ["GET", "HEAD"]:
|
|
73
|
-
try:
|
|
74
|
-
body = await request.body()
|
|
75
|
-
if body:
|
|
76
|
-
# Try to parse JSON
|
|
77
|
-
try:
|
|
78
|
-
body_text = body.decode("utf-8")
|
|
79
|
-
# Hide sensitive data (like passwords)
|
|
80
|
-
body_json = json.loads(body_text)
|
|
81
|
-
if isinstance(body_json, dict) and "params" in body_json:
|
|
82
|
-
# Replace sensitive fields with "***"
|
|
83
|
-
if isinstance(body_json["params"], dict):
|
|
84
|
-
for sensitive_field in [
|
|
85
|
-
"password",
|
|
86
|
-
"token",
|
|
87
|
-
"secret",
|
|
88
|
-
"api_key",
|
|
89
|
-
]:
|
|
90
|
-
if sensitive_field in body_json["params"]:
|
|
91
|
-
body_json["params"][sensitive_field] = "***"
|
|
92
|
-
|
|
93
|
-
req_logger.debug(f"Request body: {json.dumps(body_json)}")
|
|
94
|
-
except json.JSONDecodeError:
|
|
95
|
-
# If not JSON, log as is
|
|
96
|
-
req_logger.debug(f"Request body: {body_text}")
|
|
97
|
-
except Exception as e:
|
|
98
|
-
req_logger.warning(f"Error logging request body: {str(e)}")
|
|
99
|
-
except Exception as e:
|
|
100
|
-
req_logger.warning(f"Error reading request body: {str(e)}")
|
|
101
|
-
|
|
102
|
-
# Call the next middleware or main handler
|
|
103
|
-
try:
|
|
104
|
-
get_global_logger().debug(f"🔍 LoggingMiddleware - About to call next handler")
|
|
105
|
-
response = await call_next(request)
|
|
106
|
-
get_global_logger().debug(f"🔍 LoggingMiddleware - Next handler completed with status: {response.status_code}")
|
|
107
|
-
|
|
108
|
-
# Log request completion
|
|
109
|
-
process_time = time.time() - start_time
|
|
110
|
-
status_code = response.status_code
|
|
111
|
-
|
|
112
|
-
if is_openapi_request:
|
|
113
|
-
req_logger.debug(
|
|
114
|
-
f"Request completed: {method} {url} | Status: {status_code} | "
|
|
115
|
-
f"Time: {process_time:.3f}s"
|
|
116
|
-
)
|
|
117
|
-
else:
|
|
118
|
-
req_logger.info(
|
|
119
|
-
f"Request completed: {method} {url} | Status: {status_code} | "
|
|
120
|
-
f"Time: {process_time:.3f}s"
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
# Add request ID to response headers
|
|
124
|
-
response.headers["X-Request-ID"] = request_id
|
|
125
|
-
response.headers["X-Process-Time"] = f"{process_time:.3f}s"
|
|
126
|
-
|
|
127
|
-
return response
|
|
128
|
-
except Exception as e:
|
|
129
|
-
# Log error
|
|
130
|
-
process_time = time.time() - start_time
|
|
131
|
-
|
|
132
|
-
if is_openapi_request:
|
|
133
|
-
req_logger.debug(
|
|
134
|
-
f"Request failed: {method} {url} | Error: {str(e)} | "
|
|
135
|
-
f"Time: {process_time:.3f}s"
|
|
136
|
-
)
|
|
137
|
-
else:
|
|
138
|
-
req_logger.error(
|
|
139
|
-
f"Request failed: {method} {url} | Error: {str(e)} | "
|
|
140
|
-
f"Time: {process_time:.3f}s"
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
raise
|
|
@@ -29,41 +29,6 @@ class PerformanceMiddleware(BaseMiddleware):
|
|
|
29
29
|
self.log_interval = 100 # Log statistics every 100 requests
|
|
30
30
|
self.request_count = 0
|
|
31
31
|
|
|
32
|
-
async def dispatch(
|
|
33
|
-
self, request: Request, call_next: Callable[[Request], Awaitable[Response]]
|
|
34
|
-
) -> Response:
|
|
35
|
-
"""
|
|
36
|
-
Processes request and measures performance.
|
|
37
|
-
|
|
38
|
-
Args:
|
|
39
|
-
request: Request.
|
|
40
|
-
call_next: Next handler.
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
Response.
|
|
44
|
-
"""
|
|
45
|
-
# Measure processing time
|
|
46
|
-
start_time = time.time()
|
|
47
|
-
|
|
48
|
-
# Call the next middleware or main handler
|
|
49
|
-
response = await call_next(request)
|
|
50
|
-
|
|
51
|
-
# Calculate processing time
|
|
52
|
-
process_time = time.time() - start_time
|
|
53
|
-
|
|
54
|
-
# Save time in statistics
|
|
55
|
-
path = request.url.path
|
|
56
|
-
if path not in self.request_times:
|
|
57
|
-
self.request_times[path] = []
|
|
58
|
-
|
|
59
|
-
self.request_times[path].append(process_time)
|
|
60
|
-
|
|
61
|
-
# Logging statistics
|
|
62
|
-
self.request_count += 1
|
|
63
|
-
if self.request_count % self.log_interval == 0:
|
|
64
|
-
self._log_stats()
|
|
65
|
-
|
|
66
|
-
return response
|
|
67
32
|
|
|
68
33
|
def _log_stats(self) -> None:
|
|
69
34
|
"""
|
|
@@ -9,7 +9,7 @@ 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
|
|
12
|
+
from mcp_proxy_adapter.core.protocol_manager import ProtocolManager
|
|
13
13
|
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
14
14
|
|
|
15
15
|
|
|
@@ -64,75 +64,9 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
|
|
|
64
64
|
|
|
65
65
|
self.app_config = normalized_config
|
|
66
66
|
# Get protocol manager with current configuration
|
|
67
|
-
self.protocol_manager =
|
|
67
|
+
self.protocol_manager = ProtocolManager(normalized_config)
|
|
68
68
|
|
|
69
|
-
def update_config(self, new_config: Dict[str, Any]):
|
|
70
|
-
"""
|
|
71
|
-
Update configuration and reload protocol manager.
|
|
72
69
|
|
|
73
|
-
Args:
|
|
74
|
-
new_config: New configuration dictionary
|
|
75
|
-
"""
|
|
76
|
-
# Normalize new config
|
|
77
|
-
if hasattr(new_config, "get_all"):
|
|
78
|
-
try:
|
|
79
|
-
self.app_config = new_config.get_all()
|
|
80
|
-
except Exception:
|
|
81
|
-
self.app_config = None
|
|
82
|
-
elif hasattr(new_config, "keys"):
|
|
83
|
-
self.app_config = new_config
|
|
84
|
-
else:
|
|
85
|
-
self.app_config = None
|
|
86
|
-
self.protocol_manager = get_protocol_manager(self.app_config)
|
|
87
|
-
get_global_logger().info("Protocol middleware configuration updated")
|
|
88
|
-
|
|
89
|
-
async def dispatch(self, request: Request, call_next: Callable) -> Response:
|
|
90
|
-
"""
|
|
91
|
-
Process request through protocol middleware.
|
|
92
|
-
|
|
93
|
-
Args:
|
|
94
|
-
request: Incoming request
|
|
95
|
-
call_next: Next middleware/endpoint function
|
|
96
|
-
|
|
97
|
-
Returns:
|
|
98
|
-
Response object
|
|
99
|
-
"""
|
|
100
|
-
get_global_logger().debug(f"ProtocolMiddleware processing {request.method} {request.url.path}")
|
|
101
|
-
|
|
102
|
-
try:
|
|
103
|
-
# Get protocol from request
|
|
104
|
-
protocol = self._get_request_protocol(request)
|
|
105
|
-
get_global_logger().debug(f"Detected protocol: {protocol} for {request.method} {request.url.path}")
|
|
106
|
-
|
|
107
|
-
# Check if protocol is allowed
|
|
108
|
-
is_allowed = self.protocol_manager.is_protocol_allowed(protocol)
|
|
109
|
-
get_global_logger().debug(f"Protocol '{protocol}' allowed: {is_allowed}")
|
|
110
|
-
|
|
111
|
-
if not is_allowed:
|
|
112
|
-
get_global_logger().warning(f"Protocol '{protocol}' not allowed for request to {request.url.path}")
|
|
113
|
-
return JSONResponse(
|
|
114
|
-
status_code=403,
|
|
115
|
-
content={
|
|
116
|
-
"error": "Protocol not allowed",
|
|
117
|
-
"message": f"Protocol '{protocol}' is not allowed. Allowed protocols: {self.protocol_manager.get_allowed_protocols()}",
|
|
118
|
-
"allowed_protocols": self.protocol_manager.get_allowed_protocols(),
|
|
119
|
-
},
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
# Continue processing
|
|
123
|
-
request.state.protocol = protocol
|
|
124
|
-
get_global_logger().debug(f"Protocol '{protocol}' added to request state")
|
|
125
|
-
|
|
126
|
-
response = await call_next(request)
|
|
127
|
-
get_global_logger().debug(f"ProtocolMiddleware completed with status: {response.status_code}")
|
|
128
|
-
return response
|
|
129
|
-
|
|
130
|
-
except Exception as e:
|
|
131
|
-
get_global_logger().error(f"❌ PROTOCOL STEP ERROR: ProtocolMiddleware ERROR: {str(e)}", exc_info=True)
|
|
132
|
-
return JSONResponse(
|
|
133
|
-
status_code=500,
|
|
134
|
-
content={"error": "Protocol validation error", "message": str(e)},
|
|
135
|
-
)
|
|
136
70
|
|
|
137
71
|
def _get_request_protocol(self, request: Request) -> str:
|
|
138
72
|
"""
|
|
@@ -204,33 +138,3 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
|
|
|
204
138
|
return "http"
|
|
205
139
|
|
|
206
140
|
|
|
207
|
-
def setup_protocol_middleware(app, app_config: Optional[Dict[str, Any]] = None):
|
|
208
|
-
"""
|
|
209
|
-
Setup protocol middleware for FastAPI application.
|
|
210
|
-
|
|
211
|
-
Args:
|
|
212
|
-
app: FastAPI application
|
|
213
|
-
app_config: Application configuration dictionary (optional)
|
|
214
|
-
"""
|
|
215
|
-
# Check if protocol management is enabled
|
|
216
|
-
if app_config is None:
|
|
217
|
-
from mcp_proxy_adapter.config import config
|
|
218
|
-
app_config = config.get_all()
|
|
219
|
-
|
|
220
|
-
if hasattr(app_config, "get"):
|
|
221
|
-
protocols_config = app_config.get("protocols", {})
|
|
222
|
-
enabled = (
|
|
223
|
-
protocols_config.get("enabled", True)
|
|
224
|
-
if hasattr(protocols_config, "get")
|
|
225
|
-
else True
|
|
226
|
-
)
|
|
227
|
-
else:
|
|
228
|
-
enabled = True
|
|
229
|
-
|
|
230
|
-
if enabled:
|
|
231
|
-
# Create protocol middleware with current configuration
|
|
232
|
-
middleware = ProtocolMiddleware(app, app_config)
|
|
233
|
-
app.add_middleware(ProtocolMiddleware, app_config=app_config)
|
|
234
|
-
get_global_logger().info("Protocol middleware added to application")
|
|
235
|
-
else:
|
|
236
|
-
get_global_logger().info("Protocol management is disabled, skipping protocol middleware")
|
|
@@ -27,43 +27,6 @@ class TransportMiddleware(BaseHTTPMiddleware):
|
|
|
27
27
|
super().__init__(app)
|
|
28
28
|
self.transport_manager = transport_manager_instance or transport_manager
|
|
29
29
|
|
|
30
|
-
async def dispatch(self, request: Request, call_next: Callable) -> Response:
|
|
31
|
-
"""
|
|
32
|
-
Process request through transport middleware.
|
|
33
|
-
|
|
34
|
-
Args:
|
|
35
|
-
request: Incoming request
|
|
36
|
-
call_next: Next middleware/endpoint
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
Response from next middleware/endpoint or error response
|
|
40
|
-
"""
|
|
41
|
-
# Determine transport type from request
|
|
42
|
-
transport_type = self._get_request_transport_type(request)
|
|
43
|
-
|
|
44
|
-
# Check if request matches configured transport
|
|
45
|
-
if not self._is_transport_allowed(transport_type):
|
|
46
|
-
configured_type = self.transport_manager.get_transport_type()
|
|
47
|
-
configured_type_str = (
|
|
48
|
-
configured_type.value if configured_type else "not configured"
|
|
49
|
-
)
|
|
50
|
-
get_global_logger().warning(f"Transport not allowed: {transport_type} for {request.url}")
|
|
51
|
-
return JSONResponse(
|
|
52
|
-
status_code=403,
|
|
53
|
-
content={
|
|
54
|
-
"error": "Transport not allowed",
|
|
55
|
-
"message": f"Transport '{transport_type}' is not allowed. Configured transport: {configured_type_str}",
|
|
56
|
-
"configured_transport": configured_type_str,
|
|
57
|
-
"request_url": str(request.url),
|
|
58
|
-
},
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
# Add transport info to request state
|
|
62
|
-
request.state.transport_type = transport_type
|
|
63
|
-
request.state.transport_allowed = True
|
|
64
|
-
|
|
65
|
-
response = await call_next(request)
|
|
66
|
-
return response
|
|
67
30
|
|
|
68
31
|
def _get_request_transport_type(self, request: Request) -> str:
|
|
69
32
|
"""
|
|
@@ -10,17 +10,15 @@ email: vasilyvz@gmail.com
|
|
|
10
10
|
|
|
11
11
|
import time
|
|
12
12
|
import logging
|
|
13
|
-
from typing import Dict, Any,
|
|
13
|
+
from typing import Dict, Any, Callable, Awaitable
|
|
14
14
|
from fastapi import Request, Response
|
|
15
15
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
16
16
|
|
|
17
17
|
# Direct import from framework
|
|
18
18
|
try:
|
|
19
|
-
from mcp_security_framework.middleware
|
|
19
|
+
from mcp_security_framework.middleware import (
|
|
20
20
|
FastAPISecurityMiddleware,
|
|
21
21
|
)
|
|
22
|
-
from mcp_security_framework import SecurityManager
|
|
23
|
-
from mcp_security_framework.schemas.config import SecurityConfig
|
|
24
22
|
|
|
25
23
|
SECURITY_FRAMEWORK_AVAILABLE = True
|
|
26
24
|
except ImportError as e:
|
|
@@ -31,7 +29,7 @@ except ImportError as e:
|
|
|
31
29
|
) from e
|
|
32
30
|
|
|
33
31
|
from mcp_proxy_adapter.core.logging import get_global_logger
|
|
34
|
-
from mcp_proxy_adapter.core.security_integration import create_security_integration
|
|
32
|
+
# from mcp_proxy_adapter.core.security_integration import create_security_integration
|
|
35
33
|
|
|
36
34
|
|
|
37
35
|
class SecurityValidationError(Exception):
|
|
@@ -70,12 +68,14 @@ class UnifiedSecurityMiddleware(BaseHTTPMiddleware):
|
|
|
70
68
|
security_enabled = security_config.get("enabled", False)
|
|
71
69
|
|
|
72
70
|
if security_enabled:
|
|
73
|
-
self.security_integration = create_security_integration(security_config)
|
|
71
|
+
# self.security_integration = create_security_integration(security_config)
|
|
72
|
+
self.security_integration = None
|
|
74
73
|
# Use framework's FastAPI middleware
|
|
75
|
-
self.framework_middleware = (
|
|
76
|
-
|
|
77
|
-
)
|
|
78
|
-
|
|
74
|
+
# self.framework_middleware = (
|
|
75
|
+
# self.security_integration.security_manager.create_fastapi_middleware()
|
|
76
|
+
# )
|
|
77
|
+
self.framework_middleware = None
|
|
78
|
+
get_global_logger().info("Security disabled - no middleware")
|
|
79
79
|
# IMPORTANT: Don't replace self.app! This breaks the middleware chain.
|
|
80
80
|
# Instead, store the framework middleware for use in dispatch method.
|
|
81
81
|
get_global_logger().info("Framework middleware will be used in dispatch method")
|