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
@@ -13,7 +13,7 @@ class CommandResult(ABC):
|
|
13
13
|
"""
|
14
14
|
Base abstract class for command execution results.
|
15
15
|
"""
|
16
|
-
|
16
|
+
|
17
17
|
@abstractmethod
|
18
18
|
def to_dict(self) -> Dict[str, Any]:
|
19
19
|
"""
|
@@ -23,7 +23,7 @@ class CommandResult(ABC):
|
|
23
23
|
Dictionary with result data.
|
24
24
|
"""
|
25
25
|
pass
|
26
|
-
|
26
|
+
|
27
27
|
@classmethod
|
28
28
|
@abstractmethod
|
29
29
|
def get_schema(cls) -> Dict[str, Any]:
|
@@ -34,7 +34,7 @@ class CommandResult(ABC):
|
|
34
34
|
Dictionary with JSON schema.
|
35
35
|
"""
|
36
36
|
pass
|
37
|
-
|
37
|
+
|
38
38
|
def to_json(self, indent: Optional[int] = None) -> str:
|
39
39
|
"""
|
40
40
|
Converts result to JSON string.
|
@@ -46,7 +46,7 @@ class CommandResult(ABC):
|
|
46
46
|
JSON string with result.
|
47
47
|
"""
|
48
48
|
return json.dumps(self.to_dict(), ensure_ascii=False, indent=indent)
|
49
|
-
|
49
|
+
|
50
50
|
@classmethod
|
51
51
|
def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
|
52
52
|
"""
|
@@ -66,8 +66,10 @@ class SuccessResult(CommandResult):
|
|
66
66
|
"""
|
67
67
|
Base class for successful command results.
|
68
68
|
"""
|
69
|
-
|
70
|
-
def __init__(
|
69
|
+
|
70
|
+
def __init__(
|
71
|
+
self, data: Optional[Dict[str, Any]] = None, message: Optional[str] = None
|
72
|
+
):
|
71
73
|
"""
|
72
74
|
Initialize successful result.
|
73
75
|
|
@@ -77,7 +79,7 @@ class SuccessResult(CommandResult):
|
|
77
79
|
"""
|
78
80
|
self.data = data or {}
|
79
81
|
self.message = message
|
80
|
-
|
82
|
+
|
81
83
|
def to_dict(self) -> Dict[str, Any]:
|
82
84
|
"""
|
83
85
|
Converts result to dictionary for serialization.
|
@@ -91,7 +93,7 @@ class SuccessResult(CommandResult):
|
|
91
93
|
if self.message:
|
92
94
|
result["message"] = self.message
|
93
95
|
return result
|
94
|
-
|
96
|
+
|
95
97
|
@classmethod
|
96
98
|
def get_schema(cls) -> Dict[str, Any]:
|
97
99
|
"""
|
@@ -105,11 +107,11 @@ class SuccessResult(CommandResult):
|
|
105
107
|
"properties": {
|
106
108
|
"success": {"type": "boolean"},
|
107
109
|
"data": {"type": "object"},
|
108
|
-
"message": {"type": "string"}
|
110
|
+
"message": {"type": "string"},
|
109
111
|
},
|
110
|
-
"required": ["success"]
|
112
|
+
"required": ["success"],
|
111
113
|
}
|
112
|
-
|
114
|
+
|
113
115
|
@classmethod
|
114
116
|
def from_dict(cls, data: Dict[str, Any]) -> "SuccessResult":
|
115
117
|
"""
|
@@ -121,25 +123,19 @@ class SuccessResult(CommandResult):
|
|
121
123
|
Returns:
|
122
124
|
Successful result instance.
|
123
125
|
"""
|
124
|
-
return cls(
|
125
|
-
data=data.get("data"),
|
126
|
-
message=data.get("message")
|
127
|
-
)
|
126
|
+
return cls(data=data.get("data"), message=data.get("message"))
|
128
127
|
|
129
128
|
|
130
129
|
class ErrorResult(CommandResult):
|
131
130
|
"""
|
132
131
|
Base class for command results with error.
|
133
|
-
|
132
|
+
|
134
133
|
This class follows the JSON-RPC 2.0 error object format:
|
135
134
|
https://www.jsonrpc.org/specification#error_object
|
136
135
|
"""
|
137
|
-
|
136
|
+
|
138
137
|
def __init__(
|
139
|
-
self,
|
140
|
-
message: str,
|
141
|
-
code: int = -32000,
|
142
|
-
details: Optional[Dict[str, Any]] = None
|
138
|
+
self, message: str, code: int = -32000, details: Optional[Dict[str, Any]] = None
|
143
139
|
):
|
144
140
|
"""
|
145
141
|
Initialize error result.
|
@@ -153,7 +149,7 @@ class ErrorResult(CommandResult):
|
|
153
149
|
self.error = message # For backward compatibility with tests
|
154
150
|
self.code = code
|
155
151
|
self.details = details or {}
|
156
|
-
|
152
|
+
|
157
153
|
def to_dict(self) -> Dict[str, Any]:
|
158
154
|
"""
|
159
155
|
Converts result to dictionary for serialization.
|
@@ -163,15 +159,12 @@ class ErrorResult(CommandResult):
|
|
163
159
|
"""
|
164
160
|
result = {
|
165
161
|
"success": False,
|
166
|
-
"error": {
|
167
|
-
"code": self.code,
|
168
|
-
"message": self.message
|
169
|
-
}
|
162
|
+
"error": {"code": self.code, "message": self.message},
|
170
163
|
}
|
171
164
|
if self.details:
|
172
165
|
result["error"]["data"] = self.details
|
173
166
|
return result
|
174
|
-
|
167
|
+
|
175
168
|
@classmethod
|
176
169
|
def get_schema(cls) -> Dict[str, Any]:
|
177
170
|
"""
|
@@ -189,14 +182,14 @@ class ErrorResult(CommandResult):
|
|
189
182
|
"properties": {
|
190
183
|
"code": {"type": "integer"},
|
191
184
|
"message": {"type": "string"},
|
192
|
-
"data": {"type": "object"}
|
185
|
+
"data": {"type": "object"},
|
193
186
|
},
|
194
|
-
"required": ["code", "message"]
|
195
|
-
}
|
187
|
+
"required": ["code", "message"],
|
188
|
+
},
|
196
189
|
},
|
197
|
-
"required": ["success", "error"]
|
190
|
+
"required": ["success", "error"],
|
198
191
|
}
|
199
|
-
|
192
|
+
|
200
193
|
@classmethod
|
201
194
|
def from_dict(cls, data: Dict[str, Any]) -> "ErrorResult":
|
202
195
|
"""
|
@@ -212,5 +205,5 @@ class ErrorResult(CommandResult):
|
|
212
205
|
return cls(
|
213
206
|
message=error.get("message", "Unknown error"),
|
214
207
|
code=error.get("code", -32000),
|
215
|
-
details=error.get("data")
|
208
|
+
details=error.get("data"),
|
216
209
|
)
|
@@ -18,11 +18,11 @@ logger = logging.getLogger(__name__)
|
|
18
18
|
|
19
19
|
class RoleTestCommandResult(SuccessResult):
|
20
20
|
"""Result for role test command."""
|
21
|
-
|
21
|
+
|
22
22
|
def __init__(self, user_role: str, permissions: list, action: str, allowed: bool):
|
23
23
|
"""
|
24
24
|
Initialize role test result.
|
25
|
-
|
25
|
+
|
26
26
|
Args:
|
27
27
|
user_role: User's role
|
28
28
|
permissions: User's permissions
|
@@ -34,7 +34,7 @@ class RoleTestCommandResult(SuccessResult):
|
|
34
34
|
self.permissions = permissions
|
35
35
|
self.action = action
|
36
36
|
self.allowed = allowed
|
37
|
-
|
37
|
+
|
38
38
|
def to_dict(self) -> Dict[str, Any]:
|
39
39
|
"""Convert to dictionary."""
|
40
40
|
return {
|
@@ -43,11 +43,11 @@ class RoleTestCommandResult(SuccessResult):
|
|
43
43
|
"user_role": self.user_role,
|
44
44
|
"permissions": self.permissions,
|
45
45
|
"action": self.action,
|
46
|
-
"allowed": self.allowed
|
46
|
+
"allowed": self.allowed,
|
47
47
|
},
|
48
|
-
"message": f"Action '{self.action}' {'allowed' if self.allowed else 'denied'} for role '{self.user_role}'"
|
48
|
+
"message": f"Action '{self.action}' {'allowed' if self.allowed else 'denied'} for role '{self.user_role}'",
|
49
49
|
}
|
50
|
-
|
50
|
+
|
51
51
|
@classmethod
|
52
52
|
def get_schema(cls) -> Dict[str, Any]:
|
53
53
|
"""Get JSON schema."""
|
@@ -61,53 +61,53 @@ class RoleTestCommandResult(SuccessResult):
|
|
61
61
|
"user_role": {"type": "string"},
|
62
62
|
"permissions": {"type": "array", "items": {"type": "string"}},
|
63
63
|
"action": {"type": "string"},
|
64
|
-
"allowed": {"type": "boolean"}
|
65
|
-
}
|
64
|
+
"allowed": {"type": "boolean"},
|
65
|
+
},
|
66
66
|
},
|
67
|
-
"message": {"type": "string"}
|
68
|
-
}
|
67
|
+
"message": {"type": "string"},
|
68
|
+
},
|
69
69
|
}
|
70
70
|
|
71
71
|
|
72
72
|
class RoleTestCommand(Command):
|
73
73
|
"""Test role-based access control."""
|
74
|
-
|
74
|
+
|
75
75
|
name = "roletest"
|
76
76
|
descr = "Test role-based access control"
|
77
77
|
category = "security"
|
78
78
|
author = "Vasiliy Zdanovskiy"
|
79
79
|
email = "vasilyvz@gmail.com"
|
80
|
-
|
80
|
+
|
81
81
|
async def execute(self, **kwargs) -> RoleTestCommandResult:
|
82
82
|
"""
|
83
83
|
Execute role test command.
|
84
|
-
|
84
|
+
|
85
85
|
Args:
|
86
86
|
**kwargs: Command parameters including context
|
87
|
-
|
87
|
+
|
88
88
|
Returns:
|
89
89
|
RoleTestCommandResult
|
90
90
|
"""
|
91
91
|
# Extract parameters
|
92
92
|
action = kwargs.get("action", "read")
|
93
93
|
context = kwargs.get("context", {})
|
94
|
-
|
94
|
+
|
95
95
|
# Get user info from context
|
96
96
|
user_role = "guest" # Default
|
97
97
|
permissions = ["read"] # Default
|
98
|
-
|
98
|
+
|
99
99
|
if context:
|
100
100
|
user_info = context.get("user", {})
|
101
101
|
user_role = user_info.get("role", "guest")
|
102
102
|
permissions = user_info.get("permissions", ["read"])
|
103
|
-
|
103
|
+
|
104
104
|
# Check if action is allowed
|
105
105
|
allowed = self._check_permission(action, permissions)
|
106
|
-
|
106
|
+
|
107
107
|
logger.info(f"Role test: user={user_role}, action={action}, allowed={allowed}")
|
108
|
-
|
108
|
+
|
109
109
|
return RoleTestCommandResult(user_role, permissions, action, allowed)
|
110
|
-
|
110
|
+
|
111
111
|
@classmethod
|
112
112
|
def get_schema(cls) -> Dict[str, Any]:
|
113
113
|
"""Get JSON schema for command parameters."""
|
@@ -117,26 +117,26 @@ class RoleTestCommand(Command):
|
|
117
117
|
"action": {
|
118
118
|
"type": "string",
|
119
119
|
"description": "Action to test",
|
120
|
-
"default": "read"
|
120
|
+
"default": "read",
|
121
121
|
}
|
122
122
|
},
|
123
|
-
"additionalProperties": False
|
123
|
+
"additionalProperties": False,
|
124
124
|
}
|
125
|
-
|
125
|
+
|
126
126
|
def _check_permission(self, action: str, permissions: list) -> bool:
|
127
127
|
"""
|
128
128
|
Check if action is allowed for given permissions.
|
129
|
-
|
129
|
+
|
130
130
|
Args:
|
131
131
|
action: Action to check
|
132
132
|
permissions: User permissions
|
133
|
-
|
133
|
+
|
134
134
|
Returns:
|
135
135
|
True if allowed, False otherwise
|
136
136
|
"""
|
137
137
|
# Admin has all permissions
|
138
138
|
if "*" in permissions:
|
139
139
|
return True
|
140
|
-
|
140
|
+
|
141
141
|
# Check specific permission
|
142
142
|
return action in permissions
|