mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +120 -91
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +7 -3
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
  125. mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
  126. mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
  127. mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
  128. mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
  129. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
  130. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
  131. {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +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__(self, data: Optional[Dict[str, Any]] = None, message: Optional[str] = None):
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