mcp-proxy-adapter 6.3.4__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 +7 -3
- 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.4.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.4.dist-info/RECORD +0 -143
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -20,15 +20,15 @@ logger = logging.getLogger(__name__)
|
|
20
20
|
class MTLSASGIApp:
|
21
21
|
"""
|
22
22
|
ASGI application wrapper for mTLS support.
|
23
|
-
|
23
|
+
|
24
24
|
Extracts client certificates from SSL context and stores them in ASGI scope
|
25
25
|
for access by FastAPI middleware.
|
26
26
|
"""
|
27
|
-
|
27
|
+
|
28
28
|
def __init__(self, app, ssl_config: Dict[str, Any]):
|
29
29
|
"""
|
30
30
|
Initialize MTLS ASGI app.
|
31
|
-
|
31
|
+
|
32
32
|
Args:
|
33
33
|
app: The underlying ASGI application
|
34
34
|
ssl_config: SSL configuration dictionary
|
@@ -36,13 +36,15 @@ class MTLSASGIApp:
|
|
36
36
|
self.app = app
|
37
37
|
self.ssl_config = ssl_config
|
38
38
|
self.client_cert_required = ssl_config.get("client_cert_required", True)
|
39
|
-
|
40
|
-
logger.info(
|
41
|
-
|
39
|
+
|
40
|
+
logger.info(
|
41
|
+
f"MTLS ASGI app initialized: client_cert_required={self.client_cert_required}"
|
42
|
+
)
|
43
|
+
|
42
44
|
async def __call__(self, scope: Dict[str, Any], receive, send):
|
43
45
|
"""
|
44
46
|
Handle ASGI request with mTLS support.
|
45
|
-
|
47
|
+
|
46
48
|
Args:
|
47
49
|
scope: ASGI scope dictionary
|
48
50
|
receive: ASGI receive callable
|
@@ -55,27 +57,31 @@ class MTLSASGIApp:
|
|
55
57
|
if client_cert:
|
56
58
|
# Store certificate in scope for middleware access
|
57
59
|
scope["client_certificate"] = client_cert
|
58
|
-
logger.debug(
|
60
|
+
logger.debug(
|
61
|
+
f"Client certificate extracted: {client_cert.get('subject', {})}"
|
62
|
+
)
|
59
63
|
elif self.client_cert_required:
|
60
64
|
logger.warning("Client certificate required but not provided")
|
61
65
|
# Return 401 Unauthorized
|
62
66
|
await self._send_unauthorized_response(send)
|
63
67
|
return
|
64
|
-
|
68
|
+
|
65
69
|
# Call the underlying application
|
66
70
|
await self.app(scope, receive, send)
|
67
|
-
|
71
|
+
|
68
72
|
except Exception as e:
|
69
73
|
logger.error(f"Error in MTLS ASGI app: {e}")
|
70
74
|
await self._send_error_response(send, str(e))
|
71
|
-
|
72
|
-
def _extract_client_certificate(
|
75
|
+
|
76
|
+
def _extract_client_certificate(
|
77
|
+
self, scope: Dict[str, Any]
|
78
|
+
) -> Optional[Dict[str, Any]]:
|
73
79
|
"""
|
74
80
|
Extract client certificate from SSL context.
|
75
|
-
|
81
|
+
|
76
82
|
Args:
|
77
83
|
scope: ASGI scope dictionary
|
78
|
-
|
84
|
+
|
79
85
|
Returns:
|
80
86
|
Certificate dictionary or None if not found
|
81
87
|
"""
|
@@ -84,9 +90,9 @@ class MTLSASGIApp:
|
|
84
90
|
if not ssl_context:
|
85
91
|
logger.debug("No SSL context found in scope")
|
86
92
|
return None
|
87
|
-
|
93
|
+
|
88
94
|
# Try to get peer certificate
|
89
|
-
if hasattr(ssl_context,
|
95
|
+
if hasattr(ssl_context, "getpeercert"):
|
90
96
|
cert_data = ssl_context.getpeercert(binary_form=True)
|
91
97
|
if cert_data:
|
92
98
|
# Parse certificate
|
@@ -98,18 +104,18 @@ class MTLSASGIApp:
|
|
98
104
|
else:
|
99
105
|
logger.debug("SSL context has no getpeercert method")
|
100
106
|
return None
|
101
|
-
|
107
|
+
|
102
108
|
except Exception as e:
|
103
109
|
logger.error(f"Failed to extract client certificate: {e}")
|
104
110
|
return None
|
105
|
-
|
111
|
+
|
106
112
|
def _cert_to_dict(self, cert: x509.Certificate) -> Dict[str, Any]:
|
107
113
|
"""
|
108
114
|
Convert x509 certificate to dictionary.
|
109
|
-
|
115
|
+
|
110
116
|
Args:
|
111
117
|
cert: x509 certificate object
|
112
|
-
|
118
|
+
|
113
119
|
Returns:
|
114
120
|
Certificate dictionary
|
115
121
|
"""
|
@@ -118,12 +124,12 @@ class MTLSASGIApp:
|
|
118
124
|
subject = {}
|
119
125
|
for name in cert.subject:
|
120
126
|
subject[name.oid._name] = name.value
|
121
|
-
|
127
|
+
|
122
128
|
# Extract issuer
|
123
129
|
issuer = {}
|
124
130
|
for name in cert.issuer:
|
125
131
|
issuer[name.oid._name] = name.value
|
126
|
-
|
132
|
+
|
127
133
|
return {
|
128
134
|
"subject": subject,
|
129
135
|
"issuer": issuer,
|
@@ -133,54 +139,60 @@ class MTLSASGIApp:
|
|
133
139
|
"version": cert.version.value,
|
134
140
|
"signature_algorithm_oid": cert.signature_algorithm_oid._name,
|
135
141
|
"public_key": {
|
136
|
-
"key_size":
|
137
|
-
|
138
|
-
|
142
|
+
"key_size": (
|
143
|
+
cert.public_key().key_size
|
144
|
+
if hasattr(cert.public_key(), "key_size")
|
145
|
+
else None
|
146
|
+
),
|
147
|
+
"public_numbers": (
|
148
|
+
str(cert.public_key().public_numbers())
|
149
|
+
if hasattr(cert.public_key(), "public_numbers")
|
150
|
+
else None
|
151
|
+
),
|
152
|
+
},
|
139
153
|
}
|
140
154
|
except Exception as e:
|
141
155
|
logger.error(f"Failed to convert certificate to dict: {e}")
|
142
156
|
return {"error": str(e)}
|
143
|
-
|
157
|
+
|
144
158
|
async def _send_unauthorized_response(self, send):
|
145
159
|
"""Send 401 Unauthorized response."""
|
146
|
-
await send(
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
160
|
+
await send(
|
161
|
+
{
|
162
|
+
"type": "http.response.start",
|
163
|
+
"status": 401,
|
164
|
+
"headers": [
|
165
|
+
(b"content-type", b"application/json"),
|
166
|
+
(b"content-length", b"0"),
|
167
|
+
],
|
168
|
+
}
|
169
|
+
)
|
170
|
+
await send({"type": "http.response.body", "body": b""})
|
171
|
+
|
159
172
|
async def _send_error_response(self, send, error_message: str):
|
160
173
|
"""Send error response."""
|
161
|
-
body = f'{{"error": "{error_message}"}}'.encode(
|
162
|
-
await send(
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
})
|
174
|
+
body = f'{{"error": "{error_message}"}}'.encode("utf-8")
|
175
|
+
await send(
|
176
|
+
{
|
177
|
+
"type": "http.response.start",
|
178
|
+
"status": 500,
|
179
|
+
"headers": [
|
180
|
+
(b"content-type", b"application/json"),
|
181
|
+
(b"content-length", str(len(body)).encode()),
|
182
|
+
],
|
183
|
+
}
|
184
|
+
)
|
185
|
+
await send({"type": "http.response.body", "body": body})
|
174
186
|
|
175
187
|
|
176
188
|
def create_mtls_asgi_app(app, ssl_config: Dict[str, Any]):
|
177
189
|
"""
|
178
190
|
Create MTLS ASGI application wrapper.
|
179
|
-
|
191
|
+
|
180
192
|
Args:
|
181
193
|
app: The underlying ASGI application
|
182
194
|
ssl_config: SSL configuration dictionary
|
183
|
-
|
195
|
+
|
184
196
|
Returns:
|
185
197
|
MTLS ASGI app wrapper
|
186
198
|
"""
|