mcp-proxy-adapter 3.1.5__py3-none-any.whl → 4.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 (122) hide show
  1. mcp_proxy_adapter/api/app.py +86 -27
  2. mcp_proxy_adapter/api/handlers.py +1 -1
  3. mcp_proxy_adapter/api/middleware/error_handling.py +11 -10
  4. mcp_proxy_adapter/api/tool_integration.py +5 -2
  5. mcp_proxy_adapter/api/tools.py +3 -3
  6. mcp_proxy_adapter/commands/base.py +19 -1
  7. mcp_proxy_adapter/commands/command_registry.py +258 -6
  8. mcp_proxy_adapter/commands/help_command.py +54 -65
  9. mcp_proxy_adapter/commands/hooks.py +260 -0
  10. mcp_proxy_adapter/commands/reload_command.py +211 -0
  11. mcp_proxy_adapter/commands/reload_settings_command.py +125 -0
  12. mcp_proxy_adapter/commands/settings_command.py +189 -0
  13. mcp_proxy_adapter/config.py +16 -1
  14. mcp_proxy_adapter/core/__init__.py +44 -0
  15. mcp_proxy_adapter/core/logging.py +87 -34
  16. mcp_proxy_adapter/core/settings.py +376 -0
  17. mcp_proxy_adapter/core/utils.py +2 -2
  18. mcp_proxy_adapter/custom_openapi.py +81 -2
  19. mcp_proxy_adapter/examples/README.md +124 -0
  20. mcp_proxy_adapter/examples/__init__.py +7 -0
  21. mcp_proxy_adapter/examples/basic_server/README.md +60 -0
  22. mcp_proxy_adapter/examples/basic_server/__init__.py +7 -0
  23. mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +39 -0
  24. mcp_proxy_adapter/examples/basic_server/config.json +35 -0
  25. mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +238 -0
  26. mcp_proxy_adapter/examples/basic_server/server.py +98 -0
  27. mcp_proxy_adapter/examples/custom_commands/README.md +127 -0
  28. mcp_proxy_adapter/examples/custom_commands/__init__.py +27 -0
  29. mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +250 -0
  30. mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +6 -0
  31. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +103 -0
  32. mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +111 -0
  33. mcp_proxy_adapter/examples/custom_commands/config.json +62 -0
  34. mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +169 -0
  35. mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +215 -0
  36. mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +76 -0
  37. mcp_proxy_adapter/examples/custom_commands/custom_settings.json +96 -0
  38. mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +241 -0
  39. mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +135 -0
  40. mcp_proxy_adapter/examples/custom_commands/echo_command.py +122 -0
  41. mcp_proxy_adapter/examples/custom_commands/hooks.py +230 -0
  42. mcp_proxy_adapter/examples/custom_commands/intercept_command.py +123 -0
  43. mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +103 -0
  44. mcp_proxy_adapter/examples/custom_commands/server.py +223 -0
  45. mcp_proxy_adapter/examples/custom_commands/test_hooks.py +176 -0
  46. mcp_proxy_adapter/examples/deployment/README.md +49 -0
  47. mcp_proxy_adapter/examples/deployment/__init__.py +7 -0
  48. mcp_proxy_adapter/examples/deployment/config.development.json +8 -0
  49. {examples/basic_example → mcp_proxy_adapter/examples/deployment}/config.json +11 -7
  50. mcp_proxy_adapter/examples/deployment/config.production.json +12 -0
  51. mcp_proxy_adapter/examples/deployment/config.staging.json +11 -0
  52. mcp_proxy_adapter/examples/deployment/docker-compose.yml +31 -0
  53. mcp_proxy_adapter/examples/deployment/run.sh +43 -0
  54. mcp_proxy_adapter/examples/deployment/run_docker.sh +84 -0
  55. mcp_proxy_adapter/openapi.py +3 -2
  56. mcp_proxy_adapter/tests/api/test_custom_openapi.py +617 -0
  57. mcp_proxy_adapter/tests/api/test_handlers.py +522 -0
  58. mcp_proxy_adapter/tests/api/test_schemas.py +546 -0
  59. mcp_proxy_adapter/tests/api/test_tool_integration.py +531 -0
  60. mcp_proxy_adapter/tests/commands/test_help_command.py +8 -5
  61. mcp_proxy_adapter/tests/integration/test_cmd_integration.py +4 -5
  62. mcp_proxy_adapter/tests/test_command_registry.py +37 -1
  63. mcp_proxy_adapter/tests/unit/test_base_command.py +391 -85
  64. mcp_proxy_adapter/version.py +1 -1
  65. {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/METADATA +1 -1
  66. mcp_proxy_adapter-4.0.0.dist-info/RECORD +110 -0
  67. {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/WHEEL +1 -1
  68. {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/top_level.txt +0 -1
  69. examples/__init__.py +0 -19
  70. examples/anti_patterns/README.md +0 -51
  71. examples/anti_patterns/__init__.py +0 -9
  72. examples/anti_patterns/bad_design/README.md +0 -72
  73. examples/anti_patterns/bad_design/global_state.py +0 -170
  74. examples/anti_patterns/bad_design/monolithic_command.py +0 -272
  75. examples/basic_example/README.md +0 -245
  76. examples/basic_example/__init__.py +0 -8
  77. examples/basic_example/commands/__init__.py +0 -5
  78. examples/basic_example/commands/echo_command.py +0 -95
  79. examples/basic_example/commands/math_command.py +0 -151
  80. examples/basic_example/commands/time_command.py +0 -152
  81. examples/basic_example/docs/EN/README.md +0 -177
  82. examples/basic_example/docs/RU/README.md +0 -177
  83. examples/basic_example/server.py +0 -151
  84. examples/basic_example/tests/conftest.py +0 -243
  85. examples/check_vstl_schema.py +0 -106
  86. examples/commands/echo_command.py +0 -52
  87. examples/commands/echo_command_di.py +0 -152
  88. examples/commands/echo_result.py +0 -65
  89. examples/commands/get_date_command.py +0 -98
  90. examples/commands/new_uuid4_command.py +0 -91
  91. examples/complete_example/Dockerfile +0 -24
  92. examples/complete_example/README.md +0 -92
  93. examples/complete_example/__init__.py +0 -8
  94. examples/complete_example/commands/__init__.py +0 -5
  95. examples/complete_example/commands/system_command.py +0 -328
  96. examples/complete_example/config.json +0 -41
  97. examples/complete_example/configs/config.dev.yaml +0 -40
  98. examples/complete_example/configs/config.docker.yaml +0 -40
  99. examples/complete_example/docker-compose.yml +0 -35
  100. examples/complete_example/requirements.txt +0 -20
  101. examples/complete_example/server.py +0 -113
  102. examples/di_example/.pytest_cache/README.md +0 -8
  103. examples/di_example/server.py +0 -249
  104. examples/fix_vstl_help.py +0 -123
  105. examples/minimal_example/README.md +0 -65
  106. examples/minimal_example/__init__.py +0 -8
  107. examples/minimal_example/config.json +0 -14
  108. examples/minimal_example/main.py +0 -136
  109. examples/minimal_example/simple_server.py +0 -163
  110. examples/minimal_example/tests/conftest.py +0 -171
  111. examples/minimal_example/tests/test_hello_command.py +0 -111
  112. examples/minimal_example/tests/test_integration.py +0 -181
  113. examples/patch_vstl_service.py +0 -105
  114. examples/patch_vstl_service_mcp.py +0 -108
  115. examples/server.py +0 -69
  116. examples/simple_server.py +0 -128
  117. examples/test_package_3.1.4.py +0 -177
  118. examples/test_server.py +0 -134
  119. examples/tool_description_example.py +0 -82
  120. mcp_proxy_adapter/py.typed +0 -0
  121. mcp_proxy_adapter-3.1.5.dist-info/RECORD +0 -118
  122. {mcp_proxy_adapter-3.1.5.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,260 @@
1
+ """
2
+ Module for command execution hooks.
3
+
4
+ This module provides a hook system that allows intercepting command execution
5
+ before and after the actual command runs.
6
+ """
7
+
8
+ from typing import Any, Callable, Dict, List, Optional, Union
9
+ from dataclasses import dataclass
10
+ from enum import Enum
11
+
12
+ from mcp_proxy_adapter.core.logging import logger
13
+
14
+
15
+ class HookType(Enum):
16
+ """Types of hooks."""
17
+ BEFORE_EXECUTION = "before_execution"
18
+ AFTER_EXECUTION = "after_execution"
19
+
20
+
21
+ @dataclass
22
+ class HookContext:
23
+ """Context passed to hook functions."""
24
+ command_name: str
25
+ params: Dict[str, Any]
26
+ hook_type: HookType
27
+ standard_processing: bool = True
28
+ result: Optional[Any] = None
29
+
30
+
31
+ class CommandHooks:
32
+ """
33
+ Manages command execution hooks.
34
+ """
35
+
36
+ def __init__(self):
37
+ """Initialize hooks manager."""
38
+ self._before_hooks: Dict[str, List[Callable]] = {}
39
+ self._after_hooks: Dict[str, List[Callable]] = {}
40
+ self._global_before_hooks: List[Callable] = []
41
+ self._global_after_hooks: List[Callable] = []
42
+
43
+ def register_before_hook(self, command_name: str, hook: Callable[[HookContext], None]) -> None:
44
+ """
45
+ Register a hook to be executed before command execution.
46
+
47
+ Args:
48
+ command_name: Name of the command to hook into
49
+ hook: Hook function that takes HookContext as parameter
50
+ """
51
+ if command_name not in self._before_hooks:
52
+ self._before_hooks[command_name] = []
53
+ self._before_hooks[command_name].append(hook)
54
+ logger.debug(f"Registered before hook for command: {command_name}")
55
+
56
+ def register_after_hook(self, command_name: str, hook: Callable[[HookContext], None]) -> None:
57
+ """
58
+ Register a hook to be executed after command execution.
59
+
60
+ Args:
61
+ command_name: Name of the command to hook into
62
+ hook: Hook function that takes HookContext as parameter
63
+ """
64
+ if command_name not in self._after_hooks:
65
+ self._after_hooks[command_name] = []
66
+ self._after_hooks[command_name].append(hook)
67
+ logger.debug(f"Registered after hook for command: {command_name}")
68
+
69
+ def register_global_before_hook(self, hook: Callable[[HookContext], None]) -> None:
70
+ """
71
+ Register a global hook to be executed before any command.
72
+
73
+ Args:
74
+ hook: Hook function that takes HookContext as parameter
75
+ """
76
+ self._global_before_hooks.append(hook)
77
+ logger.debug("Registered global before hook")
78
+
79
+ def register_global_after_hook(self, hook: Callable[[HookContext], None]) -> None:
80
+ """
81
+ Register a global hook to be executed after any command.
82
+
83
+ Args:
84
+ hook: Hook function that takes HookContext as parameter
85
+ """
86
+ self._global_after_hooks.append(hook)
87
+ logger.debug("Registered global after hook")
88
+
89
+ def unregister_before_hook(self, command_name: str, hook: Callable[[HookContext], None]) -> None:
90
+ """
91
+ Unregister a before hook for a specific command.
92
+
93
+ Args:
94
+ command_name: Name of the command
95
+ hook: Hook function to unregister
96
+ """
97
+ if command_name in self._before_hooks:
98
+ try:
99
+ self._before_hooks[command_name].remove(hook)
100
+ logger.debug(f"Unregistered before hook for command: {command_name}")
101
+ # Remove the command key if no hooks remain
102
+ if not self._before_hooks[command_name]:
103
+ del self._before_hooks[command_name]
104
+ except ValueError:
105
+ logger.warning(f"Hook not found for command: {command_name}")
106
+
107
+ def unregister_after_hook(self, command_name: str, hook: Callable[[HookContext], None]) -> None:
108
+ """
109
+ Unregister an after hook for a specific command.
110
+
111
+ Args:
112
+ command_name: Name of the command
113
+ hook: Hook function to unregister
114
+ """
115
+ if command_name in self._after_hooks:
116
+ try:
117
+ self._after_hooks[command_name].remove(hook)
118
+ logger.debug(f"Unregistered after hook for command: {command_name}")
119
+ # Remove the command key if no hooks remain
120
+ if not self._after_hooks[command_name]:
121
+ del self._after_hooks[command_name]
122
+ except ValueError:
123
+ logger.warning(f"Hook not found for command: {command_name}")
124
+
125
+ def unregister_global_before_hook(self, hook: Callable[[HookContext], None]) -> None:
126
+ """
127
+ Unregister a global before hook.
128
+
129
+ Args:
130
+ hook: Hook function to unregister
131
+ """
132
+ try:
133
+ self._global_before_hooks.remove(hook)
134
+ logger.debug("Unregistered global before hook")
135
+ except ValueError:
136
+ logger.warning("Global before hook not found")
137
+
138
+ def unregister_global_after_hook(self, hook: Callable[[HookContext], None]) -> None:
139
+ """
140
+ Unregister a global after hook.
141
+
142
+ Args:
143
+ hook: Hook function to unregister
144
+ """
145
+ try:
146
+ self._global_after_hooks.remove(hook)
147
+ logger.debug("Unregistered global after hook")
148
+ except ValueError:
149
+ logger.warning("Global after hook not found")
150
+
151
+ def execute_before_hooks(self, command_name: str, params: Dict[str, Any]) -> HookContext:
152
+ """
153
+ Execute all before hooks for a command.
154
+
155
+ Args:
156
+ command_name: Name of the command
157
+ params: Command parameters
158
+
159
+ Returns:
160
+ HookContext with execution results
161
+ """
162
+ context = HookContext(
163
+ command_name=command_name,
164
+ params=params,
165
+ hook_type=HookType.BEFORE_EXECUTION
166
+ )
167
+
168
+ # Execute global before hooks
169
+ for hook in self._global_before_hooks:
170
+ try:
171
+ hook(context)
172
+ except Exception as e:
173
+ logger.error(f"Error in global before hook for command {command_name}: {e}")
174
+
175
+ # Execute command-specific before hooks
176
+ if command_name in self._before_hooks:
177
+ for hook in self._before_hooks[command_name]:
178
+ try:
179
+ hook(context)
180
+ except Exception as e:
181
+ logger.error(f"Error in before hook for command {command_name}: {e}")
182
+
183
+ return context
184
+
185
+ def execute_after_hooks(self, command_name: str, params: Dict[str, Any], result: Any) -> HookContext:
186
+ """
187
+ Execute all after hooks for a command.
188
+
189
+ Args:
190
+ command_name: Name of the command
191
+ params: Command parameters
192
+ result: Command execution result
193
+
194
+ Returns:
195
+ HookContext with execution results
196
+ """
197
+ context = HookContext(
198
+ command_name=command_name,
199
+ params=params,
200
+ hook_type=HookType.AFTER_EXECUTION,
201
+ result=result
202
+ )
203
+
204
+ # Execute command-specific after hooks
205
+ if command_name in self._after_hooks:
206
+ for hook in self._after_hooks[command_name]:
207
+ try:
208
+ hook(context)
209
+ except Exception as e:
210
+ logger.error(f"Error in after hook for command {command_name}: {e}")
211
+
212
+ # Execute global after hooks
213
+ for hook in self._global_after_hooks:
214
+ try:
215
+ hook(context)
216
+ except Exception as e:
217
+ logger.error(f"Error in global after hook for command {command_name}: {e}")
218
+
219
+ return context
220
+
221
+ def clear_hooks(self, command_name: Optional[str] = None) -> None:
222
+ """
223
+ Clear all hooks or hooks for a specific command.
224
+
225
+ Args:
226
+ command_name: If provided, clear hooks only for this command.
227
+ If None, clear all hooks.
228
+ """
229
+ if command_name is None:
230
+ # Clear all hooks
231
+ self._before_hooks.clear()
232
+ self._after_hooks.clear()
233
+ self._global_before_hooks.clear()
234
+ self._global_after_hooks.clear()
235
+ logger.debug("Cleared all hooks")
236
+ else:
237
+ # Clear hooks for specific command
238
+ if command_name in self._before_hooks:
239
+ del self._before_hooks[command_name]
240
+ if command_name in self._after_hooks:
241
+ del self._after_hooks[command_name]
242
+ logger.debug(f"Cleared hooks for command: {command_name}")
243
+
244
+ def get_hook_info(self) -> Dict[str, Any]:
245
+ """
246
+ Get information about registered hooks.
247
+
248
+ Returns:
249
+ Dictionary with hook information
250
+ """
251
+ return {
252
+ "before_hooks": {cmd: len(hooks) for cmd, hooks in self._before_hooks.items()},
253
+ "after_hooks": {cmd: len(hooks) for cmd, hooks in self._after_hooks.items()},
254
+ "global_before_hooks": len(self._global_before_hooks),
255
+ "global_after_hooks": len(self._global_after_hooks)
256
+ }
257
+
258
+
259
+ # Global hooks instance
260
+ hooks = CommandHooks()
@@ -0,0 +1,211 @@
1
+ """
2
+ Reload command for configuration and command discovery.
3
+
4
+ This command allows reloading configuration and rediscovering commands
5
+ without restarting the server.
6
+ """
7
+
8
+ from typing import Any, Dict, Optional
9
+
10
+ from mcp_proxy_adapter.commands.base import Command
11
+ from mcp_proxy_adapter.commands.command_registry import registry
12
+ from mcp_proxy_adapter.core.logging import logger
13
+
14
+
15
+ class ReloadResult:
16
+ """
17
+ Result of reload operation.
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ config_reloaded: bool,
23
+ commands_discovered: int,
24
+ custom_commands_preserved: int,
25
+ total_commands: int,
26
+ built_in_commands: int,
27
+ custom_commands: int,
28
+ server_restart_required: bool = True,
29
+ success: bool = True,
30
+ error_message: Optional[str] = None
31
+ ):
32
+ """
33
+ Initialize reload result.
34
+
35
+ Args:
36
+ config_reloaded: Whether configuration was reloaded successfully
37
+ commands_discovered: Number of commands discovered
38
+ custom_commands_preserved: Number of custom commands preserved
39
+ total_commands: Total number of commands after reload
40
+ built_in_commands: Number of built-in commands
41
+ custom_commands: Number of custom commands
42
+ server_restart_required: Whether server restart is required
43
+ success: Whether reload was successful
44
+ error_message: Error message if reload failed
45
+ """
46
+ self.config_reloaded = config_reloaded
47
+ self.commands_discovered = commands_discovered
48
+ self.custom_commands_preserved = custom_commands_preserved
49
+ self.total_commands = total_commands
50
+ self.built_in_commands = built_in_commands
51
+ self.custom_commands = custom_commands
52
+ self.server_restart_required = server_restart_required
53
+ self.success = success
54
+ self.error_message = error_message
55
+
56
+ def to_dict(self) -> Dict[str, Any]:
57
+ """
58
+ Convert result to dictionary.
59
+
60
+ Returns:
61
+ Dictionary representation of the result.
62
+ """
63
+ return {
64
+ "success": self.success,
65
+ "config_reloaded": self.config_reloaded,
66
+ "commands_discovered": self.commands_discovered,
67
+ "custom_commands_preserved": self.custom_commands_preserved,
68
+ "total_commands": self.total_commands,
69
+ "built_in_commands": self.built_in_commands,
70
+ "custom_commands": self.custom_commands,
71
+ "server_restart_required": self.server_restart_required,
72
+ "message": "Server restart required to apply configuration changes",
73
+ "error_message": self.error_message
74
+ }
75
+
76
+ def get_schema(self) -> Dict[str, Any]:
77
+ """
78
+ Get JSON schema for the result.
79
+
80
+ Returns:
81
+ JSON schema dictionary.
82
+ """
83
+ return {
84
+ "type": "object",
85
+ "properties": {
86
+ "success": {
87
+ "type": "boolean",
88
+ "description": "Whether reload was successful"
89
+ },
90
+ "config_reloaded": {
91
+ "type": "boolean",
92
+ "description": "Whether configuration was reloaded successfully"
93
+ },
94
+ "commands_discovered": {
95
+ "type": "integer",
96
+ "description": "Number of commands discovered"
97
+ },
98
+ "custom_commands_preserved": {
99
+ "type": "integer",
100
+ "description": "Number of custom commands preserved"
101
+ },
102
+ "total_commands": {
103
+ "type": "integer",
104
+ "description": "Total number of commands after reload"
105
+ },
106
+ "built_in_commands": {
107
+ "type": "integer",
108
+ "description": "Number of built-in commands"
109
+ },
110
+ "custom_commands": {
111
+ "type": "integer",
112
+ "description": "Number of custom commands"
113
+ },
114
+ "server_restart_required": {
115
+ "type": "boolean",
116
+ "description": "Whether server restart is required to apply changes"
117
+ },
118
+ "message": {
119
+ "type": "string",
120
+ "description": "Information message about the reload operation"
121
+ },
122
+ "error_message": {
123
+ "type": ["string", "null"],
124
+ "description": "Error message if reload failed"
125
+ }
126
+ },
127
+ "required": [
128
+ "success", "config_reloaded", "commands_discovered",
129
+ "custom_commands_preserved", "total_commands",
130
+ "built_in_commands", "custom_commands", "server_restart_required"
131
+ ]
132
+ }
133
+
134
+
135
+ class ReloadCommand(Command):
136
+ """
137
+ Command for reloading configuration and rediscovering commands.
138
+ Note: This command will trigger a server restart to apply configuration changes.
139
+ """
140
+
141
+ name = "reload"
142
+
143
+ async def execute(self, **params) -> ReloadResult:
144
+ """
145
+ Execute reload command.
146
+
147
+ Args:
148
+ **params: Command parameters (currently unused)
149
+
150
+ Returns:
151
+ ReloadResult with reload information
152
+ """
153
+ try:
154
+ logger.info("🔄 Starting configuration and commands reload...")
155
+
156
+ # Perform reload
157
+ reload_info = registry.reload_config_and_commands()
158
+
159
+ # Create result
160
+ result = ReloadResult(
161
+ config_reloaded=reload_info.get("config_reloaded", False),
162
+ commands_discovered=reload_info.get("commands_discovered", 0),
163
+ custom_commands_preserved=reload_info.get("custom_commands_preserved", 0),
164
+ total_commands=reload_info.get("total_commands", 0),
165
+ built_in_commands=reload_info.get("built_in_commands", 0),
166
+ custom_commands=reload_info.get("custom_commands", 0),
167
+ server_restart_required=True,
168
+ success=True
169
+ )
170
+
171
+ logger.info(f"✅ Reload completed successfully: {result.to_dict()}")
172
+ return result
173
+
174
+ except Exception as e:
175
+ logger.error(f"❌ Reload failed: {str(e)}")
176
+ return ReloadResult(
177
+ config_reloaded=False,
178
+ commands_discovered=0,
179
+ custom_commands_preserved=0,
180
+ total_commands=0,
181
+ built_in_commands=0,
182
+ custom_commands=0,
183
+ server_restart_required=False,
184
+ success=False,
185
+ error_message=str(e)
186
+ )
187
+
188
+ @classmethod
189
+ def get_schema(cls) -> Dict[str, Any]:
190
+ """
191
+ Get JSON schema for command parameters.
192
+
193
+ Returns:
194
+ JSON schema dictionary.
195
+ """
196
+ return {
197
+ "type": "object",
198
+ "properties": {
199
+ "package_path": {
200
+ "type": "string",
201
+ "description": "Path to package with commands to discover",
202
+ "default": "mcp_proxy_adapter.commands"
203
+ },
204
+ "force_restart": {
205
+ "type": "boolean",
206
+ "description": "Force server restart to apply configuration changes",
207
+ "default": True
208
+ }
209
+ },
210
+ "additionalProperties": False
211
+ }
@@ -0,0 +1,125 @@
1
+ """
2
+ Reload Settings Command
3
+
4
+ This command allows reloading configuration settings from files and environment variables.
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from mcp_proxy_adapter.commands.base import Command
9
+ from mcp_proxy_adapter.core.settings import reload_settings, get_custom_settings
10
+ from mcp_proxy_adapter.core.logging import get_logger
11
+
12
+
13
+ class ReloadSettingsResult:
14
+ """
15
+ Result class for reload settings command.
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ success: bool,
21
+ message: str,
22
+ custom_settings: Dict[str, Any] = None,
23
+ error_message: str = None
24
+ ):
25
+ self.success = success
26
+ self.message = message
27
+ self.custom_settings = custom_settings or {}
28
+ self.error_message = error_message
29
+
30
+ def to_dict(self) -> Dict[str, Any]:
31
+ """Convert result to dictionary."""
32
+ result = {
33
+ "success": self.success,
34
+ "message": self.message,
35
+ "custom_settings": self.custom_settings
36
+ }
37
+ if self.error_message:
38
+ result["error_message"] = self.error_message
39
+ return result
40
+
41
+ def get_schema(self) -> Dict[str, Any]:
42
+ """Get JSON schema for the result."""
43
+ return {
44
+ "type": "object",
45
+ "properties": {
46
+ "success": {
47
+ "type": "boolean",
48
+ "description": "Whether the operation was successful"
49
+ },
50
+ "message": {
51
+ "type": "string",
52
+ "description": "Operation result message"
53
+ },
54
+ "custom_settings": {
55
+ "type": "object",
56
+ "description": "Current custom settings after reload",
57
+ "additionalProperties": True
58
+ },
59
+ "error_message": {
60
+ "type": "string",
61
+ "description": "Error message if operation failed"
62
+ }
63
+ },
64
+ "required": ["success", "message", "custom_settings"]
65
+ }
66
+
67
+
68
+ class ReloadSettingsCommand(Command):
69
+ """
70
+ Command to reload configuration settings.
71
+ """
72
+
73
+ name = "reload_settings"
74
+ description = "Reload configuration settings from files and environment variables"
75
+
76
+ async def execute(self, **params) -> ReloadSettingsResult:
77
+ """
78
+ Execute the reload settings command.
79
+
80
+ Args:
81
+ **params: Command parameters (not used)
82
+
83
+ Returns:
84
+ ReloadSettingsResult with operation status
85
+ """
86
+ logger = get_logger("reload_settings_command")
87
+
88
+ try:
89
+ logger.info("🔄 Starting settings reload...")
90
+
91
+ # Reload configuration from files and environment variables
92
+ reload_settings()
93
+
94
+ # Get current custom settings
95
+ custom_settings = get_custom_settings()
96
+
97
+ logger.info("✅ Settings reloaded successfully")
98
+ logger.info(f"📋 Current custom settings: {custom_settings}")
99
+
100
+ return ReloadSettingsResult(
101
+ success=True,
102
+ message="Settings reloaded successfully from configuration files and environment variables",
103
+ custom_settings=custom_settings
104
+ )
105
+
106
+ except Exception as e:
107
+ error_msg = f"Failed to reload settings: {str(e)}"
108
+ logger.error(f"❌ {error_msg}")
109
+
110
+ return ReloadSettingsResult(
111
+ success=False,
112
+ message="Failed to reload settings",
113
+ custom_settings=get_custom_settings(),
114
+ error_message=error_msg
115
+ )
116
+
117
+ @classmethod
118
+ def get_schema(cls) -> Dict[str, Any]:
119
+ """Get JSON schema for the command parameters."""
120
+ return {
121
+ "type": "object",
122
+ "description": "Reload configuration settings from files and environment variables",
123
+ "properties": {},
124
+ "additionalProperties": False
125
+ }