mcp-proxy-adapter 4.1.0__py3-none-any.whl → 6.0.0__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 (101) hide show
  1. mcp_proxy_adapter/__main__.py +12 -0
  2. mcp_proxy_adapter/api/app.py +138 -11
  3. mcp_proxy_adapter/api/handlers.py +16 -1
  4. mcp_proxy_adapter/api/middleware/__init__.py +30 -29
  5. mcp_proxy_adapter/api/middleware/auth_adapter.py +235 -0
  6. mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
  7. mcp_proxy_adapter/api/middleware/factory.py +219 -0
  8. mcp_proxy_adapter/api/middleware/logging.py +32 -6
  9. mcp_proxy_adapter/api/middleware/mtls_adapter.py +305 -0
  10. mcp_proxy_adapter/api/middleware/mtls_middleware.py +296 -0
  11. mcp_proxy_adapter/api/middleware/protocol_middleware.py +135 -0
  12. mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +241 -0
  13. mcp_proxy_adapter/api/middleware/roles_adapter.py +365 -0
  14. mcp_proxy_adapter/api/middleware/roles_middleware.py +381 -0
  15. mcp_proxy_adapter/api/middleware/security.py +376 -0
  16. mcp_proxy_adapter/api/middleware/token_auth_middleware.py +261 -0
  17. mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
  18. mcp_proxy_adapter/commands/__init__.py +13 -4
  19. mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
  20. mcp_proxy_adapter/commands/base.py +61 -30
  21. mcp_proxy_adapter/commands/builtin_commands.py +89 -0
  22. mcp_proxy_adapter/commands/catalog_manager.py +838 -0
  23. mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
  24. mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
  25. mcp_proxy_adapter/commands/command_registry.py +705 -345
  26. mcp_proxy_adapter/commands/dependency_manager.py +245 -0
  27. mcp_proxy_adapter/commands/health_command.py +7 -0
  28. mcp_proxy_adapter/commands/hooks.py +200 -167
  29. mcp_proxy_adapter/commands/key_management_command.py +506 -0
  30. mcp_proxy_adapter/commands/load_command.py +176 -0
  31. mcp_proxy_adapter/commands/plugins_command.py +235 -0
  32. mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
  33. mcp_proxy_adapter/commands/proxy_registration_command.py +268 -0
  34. mcp_proxy_adapter/commands/reload_command.py +48 -50
  35. mcp_proxy_adapter/commands/result.py +1 -0
  36. mcp_proxy_adapter/commands/roles_management_command.py +697 -0
  37. mcp_proxy_adapter/commands/ssl_setup_command.py +483 -0
  38. mcp_proxy_adapter/commands/token_management_command.py +529 -0
  39. mcp_proxy_adapter/commands/transport_management_command.py +144 -0
  40. mcp_proxy_adapter/commands/unload_command.py +158 -0
  41. mcp_proxy_adapter/config.py +99 -2
  42. mcp_proxy_adapter/core/auth_validator.py +606 -0
  43. mcp_proxy_adapter/core/certificate_utils.py +827 -0
  44. mcp_proxy_adapter/core/config_converter.py +405 -0
  45. mcp_proxy_adapter/core/config_validator.py +218 -0
  46. mcp_proxy_adapter/core/logging.py +11 -0
  47. mcp_proxy_adapter/core/protocol_manager.py +226 -0
  48. mcp_proxy_adapter/core/proxy_registration.py +270 -0
  49. mcp_proxy_adapter/core/role_utils.py +426 -0
  50. mcp_proxy_adapter/core/security_adapter.py +373 -0
  51. mcp_proxy_adapter/core/security_factory.py +239 -0
  52. mcp_proxy_adapter/core/settings.py +1 -0
  53. mcp_proxy_adapter/core/ssl_utils.py +233 -0
  54. mcp_proxy_adapter/core/transport_manager.py +292 -0
  55. mcp_proxy_adapter/custom_openapi.py +22 -11
  56. mcp_proxy_adapter/examples/basic_server/config.json +58 -23
  57. mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +54 -0
  58. mcp_proxy_adapter/examples/basic_server/config_http.json +70 -0
  59. mcp_proxy_adapter/examples/basic_server/config_http_only.json +52 -0
  60. mcp_proxy_adapter/examples/basic_server/config_https.json +58 -0
  61. mcp_proxy_adapter/examples/basic_server/config_mtls.json +58 -0
  62. mcp_proxy_adapter/examples/basic_server/config_ssl.json +46 -0
  63. mcp_proxy_adapter/examples/basic_server/server.py +17 -1
  64. mcp_proxy_adapter/examples/custom_commands/__init__.py +1 -1
  65. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +339 -23
  66. mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +105 -0
  67. mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +129 -0
  68. mcp_proxy_adapter/examples/custom_commands/config.json +97 -41
  69. mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +46 -0
  70. mcp_proxy_adapter/examples/custom_commands/config_https_only.json +46 -0
  71. mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +33 -0
  72. mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +46 -0
  73. mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +33 -0
  74. mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +33 -0
  75. mcp_proxy_adapter/examples/custom_commands/full_help_response.json +1 -0
  76. mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +629 -0
  77. mcp_proxy_adapter/examples/custom_commands/get_openapi.py +103 -0
  78. mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +129 -0
  79. mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +278 -0
  80. mcp_proxy_adapter/examples/custom_commands/server.py +92 -63
  81. mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +75 -0
  82. mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +299 -0
  83. mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +278 -0
  84. mcp_proxy_adapter/examples/custom_commands/test_openapi.py +27 -0
  85. mcp_proxy_adapter/examples/custom_commands/test_registry.py +23 -0
  86. mcp_proxy_adapter/examples/custom_commands/test_simple.py +19 -0
  87. mcp_proxy_adapter/examples/custom_project_example/README.md +103 -0
  88. mcp_proxy_adapter/examples/custom_project_example/README_EN.md +103 -0
  89. mcp_proxy_adapter/examples/simple_custom_commands/README.md +149 -0
  90. mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +149 -0
  91. mcp_proxy_adapter/main.py +175 -0
  92. mcp_proxy_adapter/schemas/roles_schema.json +162 -0
  93. mcp_proxy_adapter/tests/unit/test_config.py +53 -0
  94. mcp_proxy_adapter/version.py +1 -1
  95. {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/METADATA +2 -1
  96. mcp_proxy_adapter-6.0.0.dist-info/RECORD +179 -0
  97. mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
  98. mcp_proxy_adapter-4.1.0.dist-info/RECORD +0 -110
  99. {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/WHEEL +0 -0
  100. {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/licenses/LICENSE +0 -0
  101. {mcp_proxy_adapter-4.1.0.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/top_level.txt +0 -0
@@ -13,7 +13,6 @@ from mcp_proxy_adapter.core.errors import (
13
13
  CommandError, InternalError, InvalidParamsError, NotFoundError, ValidationError
14
14
  )
15
15
  from mcp_proxy_adapter.core.logging import logger
16
- from .hooks import hooks, HookContext
17
16
 
18
17
 
19
18
  T = TypeVar("T", bound=CommandResult)
@@ -26,6 +25,20 @@ class Command(ABC):
26
25
 
27
26
  # Command name for registration
28
27
  name: ClassVar[str]
28
+ # Command version (default: 0.1)
29
+ version: ClassVar[str] = "0.1"
30
+ # Plugin filename
31
+ plugin: ClassVar[str] = ""
32
+ # Command description
33
+ descr: ClassVar[str] = ""
34
+ # Command category
35
+ category: ClassVar[str] = ""
36
+ # Command author
37
+ author: ClassVar[str] = ""
38
+ # Author email
39
+ email: ClassVar[str] = ""
40
+ # Source URL
41
+ source_url: ClassVar[str] = ""
29
42
  # Result class
30
43
  result_class: ClassVar[Type[CommandResult]]
31
44
 
@@ -68,8 +81,7 @@ class Command(ABC):
68
81
  return cls.result_class.get_schema()
69
82
  return {}
70
83
 
71
- @classmethod
72
- def validate_params(cls, params: Dict[str, Any]) -> Dict[str, Any]:
84
+ def validate_params(self, params: Dict[str, Any]) -> Dict[str, Any]:
73
85
  """
74
86
  Validate command parameters.
75
87
 
@@ -100,9 +112,39 @@ class Command(ABC):
100
112
  else:
101
113
  # For most parameters, remove None values to avoid issues
102
114
  del validated_params[key]
115
+
116
+ # Get command schema to validate parameters
117
+ schema = self.get_schema()
118
+ if schema and "properties" in schema:
119
+ allowed_properties = schema["properties"].keys()
120
+
121
+ # Filter out parameters that are not in the schema
122
+ invalid_params = []
123
+ for param_name in list(validated_params.keys()):
124
+ if param_name not in allowed_properties:
125
+ invalid_params.append(param_name)
126
+ del validated_params[param_name]
127
+
128
+ # Log warning about invalid parameters
129
+ if invalid_params:
130
+ logger.warning(f"Command {self.__class__.__name__} received invalid parameters: {invalid_params}. "
131
+ f"Allowed parameters: {list(allowed_properties)}")
132
+
133
+ # Validate required parameters based on command schema
134
+ if schema and "required" in schema:
135
+ required_params = schema["required"]
136
+ missing_params = []
137
+
138
+ for param in required_params:
139
+ if param not in validated_params:
140
+ missing_params.append(param)
141
+
142
+ if missing_params:
143
+ raise ValidationError(
144
+ f"Missing required parameters: {', '.join(missing_params)}",
145
+ data={"missing_parameters": missing_params}
146
+ )
103
147
 
104
- # This is a simple implementation that can be overridden by subclasses
105
- # In real implementation this method would validate parameters against the schema
106
148
  return validated_params
107
149
 
108
150
  @classmethod
@@ -134,35 +176,17 @@ class Command(ABC):
134
176
  if kwargs is None:
135
177
  kwargs = {}
136
178
 
137
- # Parameters validation
138
- validated_params = cls.validate_params(kwargs)
139
-
140
- # Execute before hooks
141
- hook_context = hooks.execute_before_hooks(command_name, validated_params)
142
-
143
- # Check if standard processing should be skipped
144
- if not hook_context.standard_processing:
145
- logger.debug(f"Standard processing skipped for command {command_name} due to hook")
146
- # Return the params as result if standard processing is disabled
147
- return SuccessResult(data=validated_params)
148
-
149
179
  # Get command with priority (custom commands first, then built-in)
150
- priority_command_class = registry.get_priority_command(command_name)
151
- if priority_command_class is None:
180
+ command_class = registry.get_command(command_name)
181
+ if command_class is None:
152
182
  raise NotFoundError(f"Command '{command_name}' not found")
153
183
 
154
- # Check if we have a registered instance for this command
155
- if registry.has_instance(command_name):
156
- # Use existing instance with dependencies
157
- command = registry.get_command_instance(command_name)
158
- result = await command.execute(**validated_params)
159
- else:
160
- # Create new instance for commands without dependencies
161
- command = priority_command_class()
162
- result = await command.execute(**validated_params)
184
+ # Create new instance and validate parameters
185
+ command = command_class()
186
+ validated_params = command.validate_params(kwargs)
163
187
 
164
- # Execute after hooks
165
- hooks.execute_after_hooks(command_name, validated_params, result)
188
+ # Execute command with validated parameters
189
+ result = await command.execute(**validated_params)
166
190
 
167
191
  logger.debug(f"Command {cls.__name__} executed successfully")
168
192
  return result
@@ -271,6 +295,13 @@ class Command(ABC):
271
295
 
272
296
  return {
273
297
  "name": cls.name,
298
+ "version": cls.version,
299
+ "plugin": cls.plugin,
300
+ "descr": cls.descr,
301
+ "category": cls.category,
302
+ "author": cls.author,
303
+ "email": cls.email,
304
+ "source_url": cls.source_url,
274
305
  "summary": summary,
275
306
  "description": description,
276
307
  "params": param_info,
@@ -0,0 +1,89 @@
1
+ """
2
+ Module for registering built-in framework commands.
3
+
4
+ This module contains the procedure for adding predefined commands
5
+ that are part of the framework.
6
+ """
7
+
8
+ from typing import List
9
+ from mcp_proxy_adapter.commands.command_registry import registry
10
+ from mcp_proxy_adapter.commands.help_command import HelpCommand
11
+ from mcp_proxy_adapter.commands.health_command import HealthCommand
12
+ from mcp_proxy_adapter.commands.config_command import ConfigCommand
13
+ from mcp_proxy_adapter.commands.reload_command import ReloadCommand
14
+ from mcp_proxy_adapter.commands.settings_command import SettingsCommand
15
+ from mcp_proxy_adapter.commands.load_command import LoadCommand
16
+ from mcp_proxy_adapter.commands.unload_command import UnloadCommand
17
+ from mcp_proxy_adapter.commands.plugins_command import PluginsCommand
18
+ from mcp_proxy_adapter.commands.transport_management_command import TransportManagementCommand
19
+ from mcp_proxy_adapter.commands.proxy_registration_command import ProxyRegistrationCommand
20
+ from mcp_proxy_adapter.core.logging import logger
21
+
22
+
23
+ def register_builtin_commands() -> int:
24
+ """
25
+ Register all built-in framework commands.
26
+
27
+ Returns:
28
+ Number of built-in commands registered.
29
+ """
30
+ logger.debug("Registering built-in framework commands...")
31
+
32
+ builtin_commands = [
33
+ HelpCommand,
34
+ HealthCommand,
35
+ ConfigCommand,
36
+ ReloadCommand,
37
+ SettingsCommand,
38
+ LoadCommand,
39
+ UnloadCommand,
40
+ PluginsCommand,
41
+ TransportManagementCommand,
42
+ ProxyRegistrationCommand
43
+ ]
44
+
45
+ registered_count = 0
46
+
47
+ for command_class in builtin_commands:
48
+ try:
49
+ # Get command name for logging
50
+ command_name = getattr(command_class, 'name', command_class.__name__.lower())
51
+ if command_name.endswith('command'):
52
+ command_name = command_name[:-7]
53
+
54
+ # Check if command already exists (should not happen for built-in)
55
+ if registry.command_exists(command_name):
56
+ logger.warning(f"Built-in command '{command_name}' already exists, skipping")
57
+ continue
58
+
59
+ # Register the command
60
+ registry.register_builtin(command_class)
61
+ registered_count += 1
62
+ logger.debug(f"Registered built-in command: {command_name}")
63
+
64
+ except Exception as e:
65
+ logger.error(f"Failed to register built-in command {command_class.__name__}: {e}")
66
+
67
+ logger.info(f"Registered {registered_count} built-in framework commands")
68
+ return registered_count
69
+
70
+
71
+ def get_builtin_commands_list() -> list:
72
+ """
73
+ Get list of all built-in command classes.
74
+
75
+ Returns:
76
+ List of built-in command classes.
77
+ """
78
+ return [
79
+ HelpCommand,
80
+ HealthCommand,
81
+ ConfigCommand,
82
+ ReloadCommand,
83
+ SettingsCommand,
84
+ LoadCommand,
85
+ UnloadCommand,
86
+ PluginsCommand,
87
+ TransportManagementCommand,
88
+ ProxyRegistrationCommand
89
+ ]