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.
- mcp_proxy_adapter/__init__.py +9 -5
- mcp_proxy_adapter/__main__.py +1 -1
- mcp_proxy_adapter/api/app.py +227 -176
- mcp_proxy_adapter/api/handlers.py +68 -60
- mcp_proxy_adapter/api/middleware/__init__.py +7 -5
- mcp_proxy_adapter/api/middleware/base.py +19 -16
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
- mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
- mcp_proxy_adapter/api/middleware/factory.py +50 -52
- mcp_proxy_adapter/api/middleware/logging.py +46 -30
- mcp_proxy_adapter/api/middleware/performance.py +19 -16
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
- mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
- mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
- mcp_proxy_adapter/api/schemas.py +69 -43
- mcp_proxy_adapter/api/tool_integration.py +83 -63
- mcp_proxy_adapter/api/tools.py +60 -50
- mcp_proxy_adapter/commands/__init__.py +15 -6
- mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
- mcp_proxy_adapter/commands/base.py +108 -112
- mcp_proxy_adapter/commands/builtin_commands.py +28 -18
- mcp_proxy_adapter/commands/catalog_manager.py +394 -265
- mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
- mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
- mcp_proxy_adapter/commands/command_registry.py +275 -226
- mcp_proxy_adapter/commands/config_command.py +48 -33
- mcp_proxy_adapter/commands/dependency_container.py +22 -23
- mcp_proxy_adapter/commands/dependency_manager.py +65 -56
- mcp_proxy_adapter/commands/echo_command.py +15 -15
- mcp_proxy_adapter/commands/health_command.py +31 -29
- mcp_proxy_adapter/commands/help_command.py +97 -61
- mcp_proxy_adapter/commands/hooks.py +65 -49
- mcp_proxy_adapter/commands/key_management_command.py +148 -147
- mcp_proxy_adapter/commands/load_command.py +58 -40
- mcp_proxy_adapter/commands/plugins_command.py +80 -54
- mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
- mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
- mcp_proxy_adapter/commands/reload_command.py +43 -37
- mcp_proxy_adapter/commands/result.py +26 -33
- mcp_proxy_adapter/commands/role_test_command.py +26 -26
- mcp_proxy_adapter/commands/roles_management_command.py +176 -173
- mcp_proxy_adapter/commands/security_command.py +134 -122
- mcp_proxy_adapter/commands/settings_command.py +47 -56
- mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
- mcp_proxy_adapter/commands/token_management_command.py +129 -158
- mcp_proxy_adapter/commands/transport_management_command.py +41 -36
- mcp_proxy_adapter/commands/unload_command.py +42 -37
- mcp_proxy_adapter/config.py +36 -35
- mcp_proxy_adapter/core/__init__.py +19 -21
- mcp_proxy_adapter/core/app_factory.py +30 -9
- mcp_proxy_adapter/core/app_runner.py +81 -64
- mcp_proxy_adapter/core/auth_validator.py +176 -182
- mcp_proxy_adapter/core/certificate_utils.py +469 -426
- mcp_proxy_adapter/core/client.py +155 -126
- mcp_proxy_adapter/core/client_manager.py +60 -54
- mcp_proxy_adapter/core/client_security.py +108 -88
- mcp_proxy_adapter/core/config_converter.py +176 -143
- mcp_proxy_adapter/core/config_validator.py +12 -4
- mcp_proxy_adapter/core/crl_utils.py +21 -7
- mcp_proxy_adapter/core/errors.py +64 -20
- mcp_proxy_adapter/core/logging.py +34 -29
- mcp_proxy_adapter/core/mtls_asgi.py +29 -25
- mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
- mcp_proxy_adapter/core/protocol_manager.py +154 -104
- mcp_proxy_adapter/core/proxy_client.py +202 -144
- mcp_proxy_adapter/core/proxy_registration.py +12 -2
- mcp_proxy_adapter/core/role_utils.py +139 -125
- mcp_proxy_adapter/core/security_adapter.py +88 -77
- mcp_proxy_adapter/core/security_factory.py +50 -44
- mcp_proxy_adapter/core/security_integration.py +72 -24
- mcp_proxy_adapter/core/server_adapter.py +68 -64
- mcp_proxy_adapter/core/server_engine.py +71 -53
- mcp_proxy_adapter/core/settings.py +68 -58
- mcp_proxy_adapter/core/ssl_utils.py +69 -56
- mcp_proxy_adapter/core/transport_manager.py +72 -60
- mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
- mcp_proxy_adapter/core/utils.py +4 -2
- mcp_proxy_adapter/custom_openapi.py +107 -99
- mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
- mcp_proxy_adapter/examples/debug_request_state.py +38 -19
- mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
- mcp_proxy_adapter/examples/demo_client.py +48 -36
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
- mcp_proxy_adapter/examples/generate_certificates.py +31 -16
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
- mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
- mcp_proxy_adapter/examples/run_example.py +23 -5
- mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
- mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
- mcp_proxy_adapter/examples/run_security_tests.py +103 -41
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
- mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/security_test_client.py +196 -127
- mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
- mcp_proxy_adapter/examples/test_config.py +19 -4
- mcp_proxy_adapter/examples/test_config_generator.py +23 -7
- mcp_proxy_adapter/examples/test_examples.py +84 -56
- mcp_proxy_adapter/examples/universal_client.py +119 -62
- mcp_proxy_adapter/openapi.py +108 -115
- mcp_proxy_adapter/utils/config_generator.py +429 -274
- mcp_proxy_adapter/version.py +1 -2
- {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.3.5.dist-info/RECORD +143 -0
- mcp_proxy_adapter-6.3.3.dist-info/RECORD +0 -143
- {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -11,15 +11,16 @@ from fastapi import Request, Response
|
|
11
11
|
from mcp_proxy_adapter.core.logging import logger
|
12
12
|
from .base import BaseMiddleware
|
13
13
|
|
14
|
+
|
14
15
|
class PerformanceMiddleware(BaseMiddleware):
|
15
16
|
"""
|
16
17
|
Middleware for measuring performance.
|
17
18
|
"""
|
18
|
-
|
19
|
+
|
19
20
|
def __init__(self, app):
|
20
21
|
"""
|
21
22
|
Initializes performance middleware.
|
22
|
-
|
23
|
+
|
23
24
|
Args:
|
24
25
|
app: FastAPI application.
|
25
26
|
"""
|
@@ -27,47 +28,49 @@ class PerformanceMiddleware(BaseMiddleware):
|
|
27
28
|
self.request_times: Dict[str, List[float]] = {}
|
28
29
|
self.log_interval = 100 # Log statistics every 100 requests
|
29
30
|
self.request_count = 0
|
30
|
-
|
31
|
-
async def dispatch(
|
31
|
+
|
32
|
+
async def dispatch(
|
33
|
+
self, request: Request, call_next: Callable[[Request], Awaitable[Response]]
|
34
|
+
) -> Response:
|
32
35
|
"""
|
33
36
|
Processes request and measures performance.
|
34
|
-
|
37
|
+
|
35
38
|
Args:
|
36
39
|
request: Request.
|
37
40
|
call_next: Next handler.
|
38
|
-
|
41
|
+
|
39
42
|
Returns:
|
40
43
|
Response.
|
41
44
|
"""
|
42
45
|
# Measure processing time
|
43
46
|
start_time = time.time()
|
44
|
-
|
47
|
+
|
45
48
|
# Call the next middleware or main handler
|
46
49
|
response = await call_next(request)
|
47
|
-
|
50
|
+
|
48
51
|
# Calculate processing time
|
49
52
|
process_time = time.time() - start_time
|
50
|
-
|
53
|
+
|
51
54
|
# Save time in statistics
|
52
55
|
path = request.url.path
|
53
56
|
if path not in self.request_times:
|
54
57
|
self.request_times[path] = []
|
55
|
-
|
58
|
+
|
56
59
|
self.request_times[path].append(process_time)
|
57
|
-
|
60
|
+
|
58
61
|
# Logging statistics
|
59
62
|
self.request_count += 1
|
60
63
|
if self.request_count % self.log_interval == 0:
|
61
64
|
self._log_stats()
|
62
|
-
|
65
|
+
|
63
66
|
return response
|
64
|
-
|
67
|
+
|
65
68
|
def _log_stats(self) -> None:
|
66
69
|
"""
|
67
70
|
Logs performance statistics.
|
68
71
|
"""
|
69
72
|
logger.info("Performance statistics:")
|
70
|
-
|
73
|
+
|
71
74
|
for path, times in self.request_times.items():
|
72
75
|
if len(times) > 1:
|
73
76
|
avg_time = statistics.mean(times)
|
@@ -75,9 +78,9 @@ class PerformanceMiddleware(BaseMiddleware):
|
|
75
78
|
max_time = max(times)
|
76
79
|
# Calculate 95th percentile
|
77
80
|
p95_time = sorted(times)[int(len(times) * 0.95)]
|
78
|
-
|
81
|
+
|
79
82
|
logger.info(
|
80
83
|
f"Path: {path}, Requests: {len(times)}, "
|
81
84
|
f"Avg: {avg_time:.3f}s, Min: {min_time:.3f}s, "
|
82
85
|
f"Max: {max_time:.3f}s, p95: {p95_time:.3f}s"
|
83
|
-
)
|
86
|
+
)
|
@@ -16,11 +16,11 @@ from mcp_proxy_adapter.core.logging import logger
|
|
16
16
|
class ProtocolMiddleware(BaseHTTPMiddleware):
|
17
17
|
"""
|
18
18
|
Middleware for protocol validation.
|
19
|
-
|
19
|
+
|
20
20
|
This middleware checks if the incoming request protocol is allowed
|
21
21
|
based on the protocol configuration.
|
22
22
|
"""
|
23
|
-
|
23
|
+
|
24
24
|
def __init__(self, app, app_config: Optional[Dict[str, Any]] = None):
|
25
25
|
"""
|
26
26
|
Initialize protocol middleware.
|
@@ -34,48 +34,58 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
|
|
34
34
|
normalized_config: Optional[Dict[str, Any]]
|
35
35
|
if app_config is None:
|
36
36
|
normalized_config = None
|
37
|
-
elif hasattr(app_config,
|
37
|
+
elif hasattr(app_config, "get_all"):
|
38
38
|
try:
|
39
39
|
normalized_config = app_config.get_all()
|
40
40
|
except Exception as e:
|
41
|
-
logger.debug(
|
41
|
+
logger.debug(
|
42
|
+
f"ProtocolMiddleware - Error calling get_all(): {e}, type: {type(app_config)}"
|
43
|
+
)
|
42
44
|
normalized_config = None
|
43
|
-
elif hasattr(app_config,
|
45
|
+
elif hasattr(app_config, "keys"):
|
44
46
|
normalized_config = app_config # Already dict-like
|
45
47
|
else:
|
46
|
-
logger.debug(
|
48
|
+
logger.debug(
|
49
|
+
f"ProtocolMiddleware - app_config is not dict-like, type: {type(app_config)}, value: {repr(app_config)}"
|
50
|
+
)
|
47
51
|
normalized_config = None
|
48
52
|
|
49
|
-
logger.debug(
|
53
|
+
logger.debug(
|
54
|
+
f"ProtocolMiddleware - normalized_config type: {type(normalized_config)}"
|
55
|
+
)
|
50
56
|
if normalized_config:
|
51
|
-
logger.debug(
|
52
|
-
|
53
|
-
|
57
|
+
logger.debug(
|
58
|
+
f"ProtocolMiddleware - protocols in config: {'protocols' in normalized_config}"
|
59
|
+
)
|
60
|
+
if "protocols" in normalized_config:
|
61
|
+
logger.debug(
|
62
|
+
f"ProtocolMiddleware - protocols type: {type(normalized_config['protocols'])}"
|
63
|
+
)
|
54
64
|
|
55
65
|
self.app_config = normalized_config
|
56
66
|
# Get protocol manager with current configuration
|
57
67
|
self.protocol_manager = get_protocol_manager(normalized_config)
|
58
|
-
|
68
|
+
|
59
69
|
def update_config(self, new_config: Dict[str, Any]):
|
60
70
|
"""
|
61
71
|
Update configuration and reload protocol manager.
|
62
|
-
|
72
|
+
|
63
73
|
Args:
|
64
74
|
new_config: New configuration dictionary
|
65
75
|
"""
|
66
76
|
# Normalize new config
|
67
|
-
if hasattr(new_config,
|
77
|
+
if hasattr(new_config, "get_all"):
|
68
78
|
try:
|
69
79
|
self.app_config = new_config.get_all()
|
70
80
|
except Exception:
|
71
81
|
self.app_config = None
|
72
|
-
elif hasattr(new_config,
|
82
|
+
elif hasattr(new_config, "keys"):
|
73
83
|
self.app_config = new_config
|
74
84
|
else:
|
75
85
|
self.app_config = None
|
76
86
|
self.protocol_manager = get_protocol_manager(self.app_config)
|
77
87
|
logger.info("Protocol middleware configuration updated")
|
78
|
-
|
88
|
+
|
79
89
|
async def dispatch(self, request: Request, call_next: Callable) -> Response:
|
80
90
|
"""
|
81
91
|
Process request through protocol middleware.
|
@@ -87,76 +97,79 @@ class ProtocolMiddleware(BaseHTTPMiddleware):
|
|
87
97
|
Returns:
|
88
98
|
Response object
|
89
99
|
"""
|
90
|
-
logger.debug(
|
100
|
+
logger.debug(
|
101
|
+
f"ProtocolMiddleware.dispatch called for {request.method} {request.url.path}"
|
102
|
+
)
|
91
103
|
try:
|
92
104
|
# Get protocol from request
|
93
105
|
protocol = self._get_request_protocol(request)
|
94
|
-
|
106
|
+
|
95
107
|
# Check if protocol is allowed
|
96
108
|
if not self.protocol_manager.is_protocol_allowed(protocol):
|
97
|
-
logger.warning(
|
109
|
+
logger.warning(
|
110
|
+
f"Protocol '{protocol}' not allowed for request to {request.url.path}"
|
111
|
+
)
|
98
112
|
return JSONResponse(
|
99
113
|
status_code=403,
|
100
114
|
content={
|
101
115
|
"error": "Protocol not allowed",
|
102
116
|
"message": f"Protocol '{protocol}' is not allowed. Allowed protocols: {self.protocol_manager.get_allowed_protocols()}",
|
103
|
-
"allowed_protocols": self.protocol_manager.get_allowed_protocols()
|
104
|
-
}
|
117
|
+
"allowed_protocols": self.protocol_manager.get_allowed_protocols(),
|
118
|
+
},
|
105
119
|
)
|
106
|
-
|
120
|
+
|
107
121
|
# Continue processing
|
108
122
|
response = await call_next(request)
|
109
123
|
return response
|
110
|
-
|
124
|
+
|
111
125
|
except Exception as e:
|
112
126
|
logger.error(f"Protocol middleware error: {e}")
|
113
127
|
return JSONResponse(
|
114
128
|
status_code=500,
|
115
|
-
content={
|
116
|
-
"error": "Protocol validation error",
|
117
|
-
"message": str(e)
|
118
|
-
}
|
129
|
+
content={"error": "Protocol validation error", "message": str(e)},
|
119
130
|
)
|
120
|
-
|
131
|
+
|
121
132
|
def _get_request_protocol(self, request: Request) -> str:
|
122
133
|
"""
|
123
134
|
Extract protocol from request.
|
124
|
-
|
135
|
+
|
125
136
|
Args:
|
126
137
|
request: FastAPI request object
|
127
|
-
|
138
|
+
|
128
139
|
Returns:
|
129
140
|
Protocol name (http, https, mtls)
|
130
141
|
"""
|
131
142
|
# Check if request is secure (HTTPS)
|
132
143
|
if request.url.scheme:
|
133
144
|
scheme = request.url.scheme.lower()
|
134
|
-
|
145
|
+
|
135
146
|
# If HTTPS, check if client certificate is provided (MTLS)
|
136
147
|
if scheme == "https":
|
137
148
|
# Check for client certificate in headers or SSL context
|
138
|
-
if hasattr(request,
|
139
|
-
ssl_context = request.scope.get(
|
140
|
-
if ssl_context and hasattr(ssl_context,
|
149
|
+
if hasattr(request, "scope") and "ssl" in request.scope:
|
150
|
+
ssl_context = request.scope.get("ssl")
|
151
|
+
if ssl_context and hasattr(ssl_context, "getpeercert"):
|
141
152
|
try:
|
142
153
|
cert = ssl_context.getpeercert()
|
143
154
|
if cert:
|
144
155
|
return "mtls"
|
145
156
|
except:
|
146
157
|
pass
|
147
|
-
|
158
|
+
|
148
159
|
# Check for client certificate in headers
|
149
|
-
if request.headers.get("ssl-client-cert") or request.headers.get(
|
160
|
+
if request.headers.get("ssl-client-cert") or request.headers.get(
|
161
|
+
"x-client-cert"
|
162
|
+
):
|
150
163
|
return "mtls"
|
151
|
-
|
164
|
+
|
152
165
|
return "https"
|
153
|
-
|
166
|
+
|
154
167
|
return scheme
|
155
|
-
|
168
|
+
|
156
169
|
# Fallback to checking headers
|
157
170
|
if request.headers.get("x-forwarded-proto"):
|
158
171
|
return request.headers.get("x-forwarded-proto").lower()
|
159
|
-
|
172
|
+
|
160
173
|
# Default to HTTP
|
161
174
|
return "http"
|
162
175
|
|
@@ -174,28 +187,45 @@ def setup_protocol_middleware(app, app_config: Optional[Dict[str, Any]] = None):
|
|
174
187
|
# Check if protocol management is enabled
|
175
188
|
if app_config is None:
|
176
189
|
from mcp_proxy_adapter.config import config
|
177
|
-
app_config = config.get_all()
|
178
|
-
logger.debug(f"setup_protocol_middleware - loaded from global config, type: {type(app_config)}")
|
179
|
-
|
180
|
-
logger.debug(f"setup_protocol_middleware - final app_config type: {type(app_config)}")
|
181
190
|
|
182
|
-
|
183
|
-
logger.debug(
|
191
|
+
app_config = config.get_all()
|
192
|
+
logger.debug(
|
193
|
+
f"setup_protocol_middleware - loaded from global config, type: {type(app_config)}"
|
194
|
+
)
|
195
|
+
|
196
|
+
logger.debug(
|
197
|
+
f"setup_protocol_middleware - final app_config type: {type(app_config)}"
|
198
|
+
)
|
199
|
+
|
200
|
+
if hasattr(app_config, "get"):
|
201
|
+
logger.debug(
|
202
|
+
f"setup_protocol_middleware - app_config keys: {list(app_config.keys()) if hasattr(app_config, 'keys') else 'no keys'}"
|
203
|
+
)
|
184
204
|
protocols_config = app_config.get("protocols", {})
|
185
|
-
logger.debug(
|
186
|
-
|
205
|
+
logger.debug(
|
206
|
+
f"setup_protocol_middleware - protocols_config type: {type(protocols_config)}"
|
207
|
+
)
|
208
|
+
enabled = (
|
209
|
+
protocols_config.get("enabled", True)
|
210
|
+
if hasattr(protocols_config, "get")
|
211
|
+
else True
|
212
|
+
)
|
187
213
|
else:
|
188
|
-
logger.debug(
|
214
|
+
logger.debug(
|
215
|
+
f"setup_protocol_middleware - app_config is not dict-like: {repr(app_config)}"
|
216
|
+
)
|
189
217
|
enabled = True
|
190
218
|
|
191
219
|
logger.debug(f"setup_protocol_middleware - protocol management enabled: {enabled}")
|
192
220
|
|
193
221
|
if enabled:
|
194
222
|
# Create protocol middleware with current configuration
|
195
|
-
logger.debug(
|
223
|
+
logger.debug(
|
224
|
+
f"setup_protocol_middleware - creating ProtocolMiddleware with config type: {type(app_config)}"
|
225
|
+
)
|
196
226
|
middleware = ProtocolMiddleware(app, app_config)
|
197
227
|
logger.debug(f"setup_protocol_middleware - adding middleware to app")
|
198
228
|
app.add_middleware(ProtocolMiddleware, app_config=app_config)
|
199
229
|
logger.info("Protocol middleware added to application")
|
200
230
|
else:
|
201
|
-
logger.info("Protocol management is disabled, skipping protocol middleware")
|
231
|
+
logger.info("Protocol management is disabled, skipping protocol middleware")
|
@@ -15,36 +15,38 @@ from mcp_proxy_adapter.core.logging import logger
|
|
15
15
|
|
16
16
|
class TransportMiddleware(BaseHTTPMiddleware):
|
17
17
|
"""Middleware for transport validation."""
|
18
|
-
|
18
|
+
|
19
19
|
def __init__(self, app, transport_manager_instance=None):
|
20
20
|
"""
|
21
21
|
Initialize transport middleware.
|
22
|
-
|
22
|
+
|
23
23
|
Args:
|
24
24
|
app: FastAPI application
|
25
25
|
transport_manager_instance: Transport manager instance (optional)
|
26
26
|
"""
|
27
27
|
super().__init__(app)
|
28
28
|
self.transport_manager = transport_manager_instance or transport_manager
|
29
|
-
|
29
|
+
|
30
30
|
async def dispatch(self, request: Request, call_next: Callable) -> Response:
|
31
31
|
"""
|
32
32
|
Process request through transport middleware.
|
33
|
-
|
33
|
+
|
34
34
|
Args:
|
35
35
|
request: Incoming request
|
36
36
|
call_next: Next middleware/endpoint
|
37
|
-
|
37
|
+
|
38
38
|
Returns:
|
39
39
|
Response from next middleware/endpoint or error response
|
40
40
|
"""
|
41
41
|
# Determine transport type from request
|
42
42
|
transport_type = self._get_request_transport_type(request)
|
43
|
-
|
43
|
+
|
44
44
|
# Check if request matches configured transport
|
45
45
|
if not self._is_transport_allowed(transport_type):
|
46
46
|
configured_type = self.transport_manager.get_transport_type()
|
47
|
-
configured_type_str =
|
47
|
+
configured_type_str = (
|
48
|
+
configured_type.value if configured_type else "not configured"
|
49
|
+
)
|
48
50
|
logger.warning(f"Transport not allowed: {transport_type} for {request.url}")
|
49
51
|
return JSONResponse(
|
50
52
|
status_code=403,
|
@@ -52,24 +54,24 @@ class TransportMiddleware(BaseHTTPMiddleware):
|
|
52
54
|
"error": "Transport not allowed",
|
53
55
|
"message": f"Transport '{transport_type}' is not allowed. Configured transport: {configured_type_str}",
|
54
56
|
"configured_transport": configured_type_str,
|
55
|
-
"request_url": str(request.url)
|
56
|
-
}
|
57
|
+
"request_url": str(request.url),
|
58
|
+
},
|
57
59
|
)
|
58
|
-
|
60
|
+
|
59
61
|
# Add transport info to request state
|
60
62
|
request.state.transport_type = transport_type
|
61
63
|
request.state.transport_allowed = True
|
62
|
-
|
64
|
+
|
63
65
|
response = await call_next(request)
|
64
66
|
return response
|
65
|
-
|
67
|
+
|
66
68
|
def _get_request_transport_type(self, request: Request) -> str:
|
67
69
|
"""
|
68
70
|
Determine transport type from request.
|
69
|
-
|
71
|
+
|
70
72
|
Args:
|
71
73
|
request: Incoming request
|
72
|
-
|
74
|
+
|
73
75
|
Returns:
|
74
76
|
Transport type string
|
75
77
|
"""
|
@@ -79,14 +81,14 @@ class TransportMiddleware(BaseHTTPMiddleware):
|
|
79
81
|
return "mtls"
|
80
82
|
return "https"
|
81
83
|
return "http"
|
82
|
-
|
84
|
+
|
83
85
|
def _has_client_certificate(self, request: Request) -> bool:
|
84
86
|
"""
|
85
87
|
Check if request has client certificate.
|
86
|
-
|
88
|
+
|
87
89
|
Args:
|
88
90
|
request: Incoming request
|
89
|
-
|
91
|
+
|
90
92
|
Returns:
|
91
93
|
True if client certificate is present, False otherwise
|
92
94
|
"""
|
@@ -95,22 +97,22 @@ class TransportMiddleware(BaseHTTPMiddleware):
|
|
95
97
|
client_cert_header = request.headers.get("ssl-client-cert")
|
96
98
|
if client_cert_header:
|
97
99
|
return True
|
98
|
-
|
100
|
+
|
99
101
|
# Check if request has SSL client certificate context
|
100
102
|
if hasattr(request, "client") and request.client:
|
101
103
|
# In a real implementation, you would check the SSL context
|
102
104
|
# For now, we'll assume HTTPS with client cert is MTLS
|
103
105
|
return self.transport_manager.is_mtls()
|
104
|
-
|
106
|
+
|
105
107
|
return False
|
106
|
-
|
108
|
+
|
107
109
|
def _is_transport_allowed(self, transport_type: str) -> bool:
|
108
110
|
"""
|
109
111
|
Check if transport type is allowed.
|
110
|
-
|
112
|
+
|
111
113
|
Args:
|
112
114
|
transport_type: Transport type to check
|
113
|
-
|
115
|
+
|
114
116
|
Returns:
|
115
117
|
True if transport is allowed, False otherwise
|
116
118
|
"""
|
@@ -118,5 +120,5 @@ class TransportMiddleware(BaseHTTPMiddleware):
|
|
118
120
|
if not configured_type:
|
119
121
|
logger.error("Transport not configured")
|
120
122
|
return False
|
121
|
-
|
122
|
-
return transport_type == configured_type.value
|
123
|
+
|
124
|
+
return transport_type == configured_type.value
|