mcp-proxy-adapter 4.1.1__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.
- mcp_proxy_adapter/__main__.py +12 -0
- mcp_proxy_adapter/api/app.py +138 -11
- mcp_proxy_adapter/api/handlers.py +16 -1
- mcp_proxy_adapter/api/middleware/__init__.py +30 -29
- mcp_proxy_adapter/api/middleware/auth_adapter.py +235 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +9 -0
- mcp_proxy_adapter/api/middleware/factory.py +219 -0
- mcp_proxy_adapter/api/middleware/logging.py +32 -6
- mcp_proxy_adapter/api/middleware/mtls_adapter.py +305 -0
- mcp_proxy_adapter/api/middleware/mtls_middleware.py +296 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +135 -0
- mcp_proxy_adapter/api/middleware/rate_limit_adapter.py +241 -0
- mcp_proxy_adapter/api/middleware/roles_adapter.py +365 -0
- mcp_proxy_adapter/api/middleware/roles_middleware.py +381 -0
- mcp_proxy_adapter/api/middleware/security.py +376 -0
- mcp_proxy_adapter/api/middleware/token_auth_middleware.py +261 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +122 -0
- mcp_proxy_adapter/commands/__init__.py +13 -4
- mcp_proxy_adapter/commands/auth_validation_command.py +408 -0
- mcp_proxy_adapter/commands/base.py +61 -30
- mcp_proxy_adapter/commands/builtin_commands.py +89 -0
- mcp_proxy_adapter/commands/catalog_manager.py +838 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +620 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +608 -0
- mcp_proxy_adapter/commands/command_registry.py +703 -354
- mcp_proxy_adapter/commands/dependency_manager.py +245 -0
- mcp_proxy_adapter/commands/health_command.py +7 -0
- mcp_proxy_adapter/commands/hooks.py +200 -167
- mcp_proxy_adapter/commands/key_management_command.py +506 -0
- mcp_proxy_adapter/commands/load_command.py +176 -0
- mcp_proxy_adapter/commands/plugins_command.py +235 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +232 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +268 -0
- mcp_proxy_adapter/commands/reload_command.py +48 -50
- mcp_proxy_adapter/commands/result.py +1 -0
- mcp_proxy_adapter/commands/roles_management_command.py +697 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +483 -0
- mcp_proxy_adapter/commands/token_management_command.py +529 -0
- mcp_proxy_adapter/commands/transport_management_command.py +144 -0
- mcp_proxy_adapter/commands/unload_command.py +158 -0
- mcp_proxy_adapter/config.py +99 -2
- mcp_proxy_adapter/core/auth_validator.py +606 -0
- mcp_proxy_adapter/core/certificate_utils.py +827 -0
- mcp_proxy_adapter/core/config_converter.py +405 -0
- mcp_proxy_adapter/core/config_validator.py +218 -0
- mcp_proxy_adapter/core/logging.py +11 -0
- mcp_proxy_adapter/core/protocol_manager.py +226 -0
- mcp_proxy_adapter/core/proxy_registration.py +270 -0
- mcp_proxy_adapter/core/role_utils.py +426 -0
- mcp_proxy_adapter/core/security_adapter.py +373 -0
- mcp_proxy_adapter/core/security_factory.py +239 -0
- mcp_proxy_adapter/core/settings.py +1 -0
- mcp_proxy_adapter/core/ssl_utils.py +233 -0
- mcp_proxy_adapter/core/transport_manager.py +292 -0
- mcp_proxy_adapter/custom_openapi.py +22 -11
- mcp_proxy_adapter/examples/basic_server/config.json +58 -23
- mcp_proxy_adapter/examples/basic_server/config_all_protocols.json +54 -0
- mcp_proxy_adapter/examples/basic_server/config_http.json +70 -0
- mcp_proxy_adapter/examples/basic_server/config_http_only.json +52 -0
- mcp_proxy_adapter/examples/basic_server/config_https.json +58 -0
- mcp_proxy_adapter/examples/basic_server/config_mtls.json +58 -0
- mcp_proxy_adapter/examples/basic_server/config_ssl.json +46 -0
- mcp_proxy_adapter/examples/basic_server/server.py +12 -1
- mcp_proxy_adapter/examples/custom_commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +339 -23
- mcp_proxy_adapter/examples/custom_commands/auto_commands/test_command.py +105 -0
- mcp_proxy_adapter/examples/custom_commands/catalog/commands/test_command.py +129 -0
- mcp_proxy_adapter/examples/custom_commands/config.json +101 -18
- mcp_proxy_adapter/examples/custom_commands/config_all_protocols.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_https_only.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_https_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/config_mtls_only.json +46 -0
- mcp_proxy_adapter/examples/custom_commands/config_mtls_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/config_single_transport.json +33 -0
- mcp_proxy_adapter/examples/custom_commands/full_help_response.json +1 -0
- mcp_proxy_adapter/examples/custom_commands/generated_openapi.json +629 -0
- mcp_proxy_adapter/examples/custom_commands/get_openapi.py +103 -0
- mcp_proxy_adapter/examples/custom_commands/loadable_commands/test_ignored.py +129 -0
- mcp_proxy_adapter/examples/custom_commands/proxy_connection_manager.py +278 -0
- mcp_proxy_adapter/examples/custom_commands/server.py +92 -68
- mcp_proxy_adapter/examples/custom_commands/simple_openapi_server.py +75 -0
- mcp_proxy_adapter/examples/custom_commands/start_server_with_proxy_manager.py +299 -0
- mcp_proxy_adapter/examples/custom_commands/start_server_with_registration.py +278 -0
- mcp_proxy_adapter/examples/custom_commands/test_openapi.py +27 -0
- mcp_proxy_adapter/examples/custom_commands/test_registry.py +23 -0
- mcp_proxy_adapter/examples/custom_commands/test_simple.py +19 -0
- mcp_proxy_adapter/examples/custom_project_example/README.md +103 -0
- mcp_proxy_adapter/examples/custom_project_example/README_EN.md +103 -0
- mcp_proxy_adapter/examples/simple_custom_commands/README.md +149 -0
- mcp_proxy_adapter/examples/simple_custom_commands/README_EN.md +149 -0
- mcp_proxy_adapter/main.py +175 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/tests/unit/test_config.py +53 -0
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/METADATA +2 -1
- mcp_proxy_adapter-6.0.0.dist-info/RECORD +179 -0
- mcp_proxy_adapter/commands/reload_settings_command.py +0 -125
- mcp_proxy_adapter-4.1.1.dist-info/RECORD +0 -110
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/top_level.txt +0 -0
@@ -11,8 +11,11 @@ import logging
|
|
11
11
|
from typing import Dict, Any
|
12
12
|
from datetime import datetime
|
13
13
|
|
14
|
-
from mcp_proxy_adapter.commands.hooks import
|
14
|
+
from mcp_proxy_adapter.commands.hooks import hooks
|
15
15
|
from mcp_proxy_adapter.commands.result import CommandResult
|
16
|
+
from mcp_proxy_adapter.commands.hooks import HookContext
|
17
|
+
from mcp_proxy_adapter.commands.hooks import HookType
|
18
|
+
# Import will be done locally when needed to avoid circular imports
|
16
19
|
|
17
20
|
|
18
21
|
# Setup logging for advanced hooks
|
@@ -26,7 +29,7 @@ def data_transform_before_hook(context: HookContext) -> None:
|
|
26
29
|
Args:
|
27
30
|
context: Hook context with command information
|
28
31
|
"""
|
29
|
-
logger.info(f"🔄 Data transform before hook: {context
|
32
|
+
logger.info(f"🔄 Data transform before hook: {context}")
|
30
33
|
|
31
34
|
# Get original data
|
32
35
|
original_data = context.params.get("data", {})
|
@@ -54,7 +57,7 @@ def data_transform_before_hook(context: HookContext) -> None:
|
|
54
57
|
|
55
58
|
logger.info(f"📊 Original data: {original_data}")
|
56
59
|
logger.info(f"🔄 Transformed data: {transformed_data}")
|
57
|
-
|
60
|
+
|
58
61
|
|
59
62
|
def data_transform_after_hook(context: HookContext) -> None:
|
60
63
|
"""
|
@@ -63,7 +66,7 @@ def data_transform_after_hook(context: HookContext) -> None:
|
|
63
66
|
Args:
|
64
67
|
context: Hook context with command information
|
65
68
|
"""
|
66
|
-
logger.info(f"🔄 Data transform after hook: {context
|
69
|
+
logger.info(f"🔄 Data transform after hook: {context}")
|
67
70
|
|
68
71
|
if context.result and hasattr(context.result, 'transformed_data'):
|
69
72
|
# Get the transformed data from command result
|
@@ -86,7 +89,7 @@ def data_transform_after_hook(context: HookContext) -> None:
|
|
86
89
|
context.result.transformed_data = formatted_data
|
87
90
|
|
88
91
|
logger.info(f"✨ Formatted data: {formatted_data}")
|
89
|
-
|
92
|
+
|
90
93
|
|
91
94
|
def intercept_before_hook(context: HookContext) -> None:
|
92
95
|
"""
|
@@ -95,7 +98,7 @@ def intercept_before_hook(context: HookContext) -> None:
|
|
95
98
|
Args:
|
96
99
|
context: Hook context with command information
|
97
100
|
"""
|
98
|
-
logger.info(f"🚫 Intercept before hook: {context
|
101
|
+
logger.info(f"🚫 Intercept before hook: {context}")
|
99
102
|
|
100
103
|
# Check bypass flag
|
101
104
|
bypass_flag = context.params.get("bypass_flag", 1)
|
@@ -114,20 +117,19 @@ def intercept_before_hook(context: HookContext) -> None:
|
|
114
117
|
hook_data={
|
115
118
|
"intercepted_by": "intercept_before_hook",
|
116
119
|
"interception_time": datetime.now().isoformat(),
|
117
|
-
"
|
120
|
+
"bypass_flag": bypass_flag
|
118
121
|
}
|
119
122
|
)
|
120
123
|
|
121
|
-
# Set the result and
|
124
|
+
# Set the result and disable standard processing
|
122
125
|
context.result = mock_result
|
123
126
|
context.standard_processing = False
|
124
127
|
|
125
|
-
logger.info(f"
|
128
|
+
logger.info(f"🚫 Command execution bypassed, result: {mock_result}")
|
126
129
|
else:
|
127
|
-
|
128
|
-
logger.info(f"✅ Allowing normal execution - bypass_flag = {bypass_flag}")
|
130
|
+
logger.info(f"✅ Command execution allowed - bypass_flag = {bypass_flag}")
|
129
131
|
context.params["hook_processed"] = True
|
130
|
-
|
132
|
+
|
131
133
|
|
132
134
|
def intercept_after_hook(context: HookContext) -> None:
|
133
135
|
"""
|
@@ -211,40 +213,354 @@ def smart_intercept_hook(context: HookContext) -> None:
|
|
211
213
|
hook_data={
|
212
214
|
"intercepted_by": "smart_intercept_hook",
|
213
215
|
"interception_time": datetime.now().isoformat(),
|
214
|
-
"original_params": context.params.copy(),
|
215
216
|
"smart_analysis": True
|
216
217
|
}
|
217
218
|
)
|
218
219
|
|
219
|
-
# Set the result and
|
220
|
+
# Set the result and disable standard processing
|
220
221
|
context.result = mock_result
|
221
222
|
context.standard_processing = False
|
222
223
|
|
223
224
|
logger.info(f"✅ Smart interception completed")
|
224
|
-
|
225
|
+
|
225
226
|
|
226
227
|
def register_advanced_hooks(hooks_manager) -> None:
|
227
228
|
"""
|
228
|
-
Register advanced hooks with the hooks
|
229
|
+
Register advanced hooks with the hooks system.
|
229
230
|
|
230
231
|
Args:
|
231
|
-
hooks_manager:
|
232
|
+
hooks_manager: Hooks manager instance to register hooks with
|
232
233
|
"""
|
233
234
|
logger.info("🔧 Registering advanced hooks...")
|
234
235
|
|
235
|
-
# Register data
|
236
|
+
# Register data transform hooks
|
236
237
|
hooks_manager.register_before_hook("data_transform", data_transform_before_hook)
|
237
238
|
hooks_manager.register_after_hook("data_transform", data_transform_after_hook)
|
238
239
|
|
239
|
-
# Register
|
240
|
+
# Register intercept hooks
|
240
241
|
hooks_manager.register_before_hook("intercept", intercept_before_hook)
|
241
242
|
hooks_manager.register_after_hook("intercept", intercept_after_hook)
|
242
243
|
|
243
|
-
# Register
|
244
|
+
# Register global hooks
|
244
245
|
hooks_manager.register_global_before_hook(conditional_transform_hook)
|
246
|
+
hooks_manager.register_global_before_hook(smart_intercept_hook)
|
245
247
|
hooks_manager.register_global_after_hook(conditional_transform_hook)
|
246
248
|
|
247
|
-
# Register
|
248
|
-
hooks_manager.
|
249
|
+
# Register system lifecycle hooks
|
250
|
+
hooks_manager.register_before_init_hook(system_before_init_hook)
|
251
|
+
hooks_manager.register_after_init_hook(system_after_init_hook)
|
252
|
+
|
253
|
+
# Register command-specific hooks for all commands
|
254
|
+
hooks_manager.register_before_hook("echo", echo_before_hook)
|
255
|
+
hooks_manager.register_after_hook("echo", echo_after_hook)
|
256
|
+
|
257
|
+
hooks_manager.register_before_hook("help", help_before_hook)
|
258
|
+
hooks_manager.register_after_hook("help", help_after_hook)
|
259
|
+
|
260
|
+
hooks_manager.register_before_hook("health", health_before_hook)
|
261
|
+
hooks_manager.register_after_hook("health", health_after_hook)
|
262
|
+
|
263
|
+
hooks_manager.register_before_hook("config", config_before_hook)
|
264
|
+
hooks_manager.register_after_hook("config", config_after_hook)
|
265
|
+
|
266
|
+
hooks_manager.register_before_hook("load", load_before_hook)
|
267
|
+
hooks_manager.register_after_hook("load", load_after_hook)
|
268
|
+
|
269
|
+
hooks_manager.register_before_hook("unload", unload_before_hook)
|
270
|
+
hooks_manager.register_after_hook("unload", unload_after_hook)
|
271
|
+
|
272
|
+
hooks_manager.register_before_hook("reload", reload_before_hook)
|
273
|
+
hooks_manager.register_after_hook("reload", reload_after_hook)
|
274
|
+
|
275
|
+
hooks_manager.register_before_hook("plugins", plugins_before_hook)
|
276
|
+
hooks_manager.register_after_hook("plugins", plugins_after_hook)
|
277
|
+
|
278
|
+
hooks_manager.register_before_hook("settings", settings_before_hook)
|
279
|
+
hooks_manager.register_after_hook("settings", settings_after_hook)
|
280
|
+
|
281
|
+
# Register custom commands hooks
|
282
|
+
hooks_manager.register_before_hook("manual_echo", manual_echo_before_hook)
|
283
|
+
hooks_manager.register_after_hook("manual_echo", manual_echo_after_hook)
|
284
|
+
|
285
|
+
hooks_manager.register_before_hook("auto_echo", auto_echo_before_hook)
|
286
|
+
hooks_manager.register_after_hook("auto_echo", auto_echo_after_hook)
|
287
|
+
|
288
|
+
hooks_manager.register_before_hook("auto_info", auto_info_before_hook)
|
289
|
+
hooks_manager.register_after_hook("auto_info", auto_info_after_hook)
|
290
|
+
|
291
|
+
logger.info("✅ Advanced hooks registered successfully")
|
292
|
+
|
293
|
+
|
294
|
+
# ============================================================================
|
295
|
+
# SYSTEM LIFECYCLE HOOKS
|
296
|
+
# ============================================================================
|
297
|
+
|
298
|
+
def system_before_init_hook(registry) -> None:
|
299
|
+
"""
|
300
|
+
Before system initialization hook.
|
301
|
+
|
302
|
+
Args:
|
303
|
+
registry: Command registry instance
|
304
|
+
"""
|
305
|
+
logger.info("🚀 System before init hook: Preparing system initialization")
|
306
|
+
|
307
|
+
# Add initialization metadata
|
308
|
+
registry.metadata["init_start_time"] = datetime.now().isoformat()
|
309
|
+
registry.metadata["init_hooks_processed"] = True
|
310
|
+
|
311
|
+
logger.info("✅ System initialization preparation completed")
|
312
|
+
|
313
|
+
|
314
|
+
def system_after_init_hook(registry) -> None:
|
315
|
+
"""
|
316
|
+
After system initialization hook.
|
317
|
+
|
318
|
+
Args:
|
319
|
+
registry: Command registry instance
|
320
|
+
"""
|
321
|
+
logger.info("🎉 System after init hook: System initialization completed")
|
322
|
+
|
323
|
+
# Add completion metadata
|
324
|
+
registry.metadata["init_end_time"] = datetime.now().isoformat()
|
325
|
+
registry.metadata["total_commands"] = len(registry.get_all_commands())
|
326
|
+
|
327
|
+
logger.info(f"✅ System initialization completed with {registry.metadata['total_commands']} commands")
|
328
|
+
|
329
|
+
|
330
|
+
# ============================================================================
|
331
|
+
# BUILT-IN COMMAND HOOKS
|
332
|
+
# ============================================================================
|
333
|
+
|
334
|
+
def echo_before_hook(context: HookContext) -> None:
|
335
|
+
"""Before hook for echo command."""
|
336
|
+
logger.info(f"📢 Echo before hook: {context.command_name}")
|
337
|
+
|
338
|
+
# Add timestamp to message
|
339
|
+
if context.params and "message" in context.params:
|
340
|
+
original_message = context.params["message"]
|
341
|
+
context.params["message"] = f"[{datetime.now().strftime('%H:%M:%S')}] {original_message}"
|
342
|
+
context.params["_timestamp_added"] = True
|
343
|
+
|
344
|
+
context.metadata["echo_processed"] = True
|
345
|
+
|
346
|
+
|
347
|
+
def echo_after_hook(context: HookContext) -> None:
|
348
|
+
"""After hook for echo command."""
|
349
|
+
logger.info(f"📢 Echo after hook: {context.command_name}")
|
350
|
+
|
351
|
+
if context.result and hasattr(context.result, 'message'):
|
352
|
+
context.result.message = f"ECHO: {context.result.message}"
|
353
|
+
context.metadata["echo_formatted"] = True
|
354
|
+
|
355
|
+
|
356
|
+
def help_before_hook(context: HookContext) -> None:
|
357
|
+
"""Before hook for help command."""
|
358
|
+
logger.info(f"❓ Help before hook: {context.command_name}")
|
359
|
+
|
360
|
+
# Add help metadata
|
361
|
+
context.metadata["help_requested"] = True
|
362
|
+
context.metadata["help_time"] = datetime.now().isoformat()
|
363
|
+
|
364
|
+
|
365
|
+
def help_after_hook(context: HookContext) -> None:
|
366
|
+
"""After hook for help command."""
|
367
|
+
logger.info(f"❓ Help after hook: {context.command_name}")
|
368
|
+
|
369
|
+
if context.result and hasattr(context.result, 'commands_info'):
|
370
|
+
# Add hook information to help
|
371
|
+
context.result.commands_info["hooks_available"] = True
|
372
|
+
context.result.commands_info["hook_count"] = 15 # Total number of hooks
|
373
|
+
|
374
|
+
|
375
|
+
def health_before_hook(context: HookContext) -> None:
|
376
|
+
"""Before hook for health command."""
|
377
|
+
logger.info(f"🏥 Health before hook: {context.command_name}")
|
378
|
+
|
379
|
+
# Add health check metadata
|
380
|
+
context.metadata["health_check_start"] = datetime.now().isoformat()
|
381
|
+
|
382
|
+
|
383
|
+
def health_after_hook(context: HookContext) -> None:
|
384
|
+
"""After hook for health command."""
|
385
|
+
logger.info(f"🏥 Health after hook: {context.command_name}")
|
386
|
+
|
387
|
+
if context.result and hasattr(context.result, 'status'):
|
388
|
+
# Add hook health status
|
389
|
+
context.result.status["hooks_healthy"] = True
|
390
|
+
context.result.status["hook_count"] = 15
|
391
|
+
|
392
|
+
|
393
|
+
def config_before_hook(context: HookContext) -> None:
|
394
|
+
"""Before hook for config command."""
|
395
|
+
logger.info(f"⚙️ Config before hook: {context.command_name}")
|
396
|
+
|
397
|
+
# Add config operation metadata
|
398
|
+
context.metadata["config_operation"] = context.params.get("operation", "unknown")
|
399
|
+
context.metadata["config_time"] = datetime.now().isoformat()
|
400
|
+
|
401
|
+
|
402
|
+
def config_after_hook(context: HookContext) -> None:
|
403
|
+
"""After hook for config command."""
|
404
|
+
logger.info(f"⚙️ Config after hook: {context.command_name}")
|
405
|
+
|
406
|
+
if context.result and hasattr(context.result, 'config'):
|
407
|
+
# Add hook configuration
|
408
|
+
context.result.config["hooks_enabled"] = True
|
409
|
+
context.result.config["hook_system_version"] = "1.0.0"
|
410
|
+
|
411
|
+
|
412
|
+
def load_before_hook(context: HookContext) -> None:
|
413
|
+
"""Before hook for load command."""
|
414
|
+
logger.info(f"📦 Load before hook: {context.command_name}")
|
415
|
+
|
416
|
+
# Add load metadata
|
417
|
+
context.metadata["load_source"] = context.params.get("source", "unknown")
|
418
|
+
context.metadata["load_time"] = datetime.now().isoformat()
|
419
|
+
|
420
|
+
|
421
|
+
def load_after_hook(context: HookContext) -> None:
|
422
|
+
"""After hook for load command."""
|
423
|
+
logger.info(f"📦 Load after hook: {context.command_name}")
|
424
|
+
|
425
|
+
if context.result and hasattr(context.result, 'loaded_commands'):
|
426
|
+
# Add hook information to loaded commands
|
427
|
+
context.result.loaded_commands["_hooks_loaded"] = True
|
428
|
+
|
429
|
+
|
430
|
+
def unload_before_hook(context: HookContext) -> None:
|
431
|
+
"""Before hook for unload command."""
|
432
|
+
logger.info(f"🗑️ Unload before hook: {context.command_name}")
|
433
|
+
|
434
|
+
# Add unload metadata
|
435
|
+
context.metadata["unload_command"] = context.params.get("command_name", "unknown")
|
436
|
+
context.metadata["unload_time"] = datetime.now().isoformat()
|
437
|
+
|
438
|
+
|
439
|
+
def unload_after_hook(context: HookContext) -> None:
|
440
|
+
"""After hook for unload command."""
|
441
|
+
logger.info(f"🗑️ Unload after hook: {context.command_name}")
|
442
|
+
|
443
|
+
if context.result and hasattr(context.result, 'unloaded_commands'):
|
444
|
+
# Add hook information to unloaded commands
|
445
|
+
context.result.unloaded_commands["_hooks_cleaned"] = True
|
446
|
+
|
447
|
+
|
448
|
+
def reload_before_hook(context: HookContext) -> None:
|
449
|
+
"""Before hook for reload command."""
|
450
|
+
logger.info(f"🔄 Reload before hook: {context.command_name}")
|
451
|
+
|
452
|
+
# Add reload metadata
|
453
|
+
context.metadata["reload_components"] = context.params.get("components", [])
|
454
|
+
context.metadata["reload_time"] = datetime.now().isoformat()
|
455
|
+
|
456
|
+
|
457
|
+
def reload_after_hook(context: HookContext) -> None:
|
458
|
+
"""After hook for reload command."""
|
459
|
+
logger.info(f"🔄 Reload after hook: {context.command_name}")
|
460
|
+
|
461
|
+
if context.result and hasattr(context.result, 'reloaded_components'):
|
462
|
+
# Add hook information to reloaded components
|
463
|
+
context.result.reloaded_components["_hooks_reloaded"] = True
|
464
|
+
|
465
|
+
|
466
|
+
def plugins_before_hook(context: HookContext) -> None:
|
467
|
+
"""Before hook for plugins command."""
|
468
|
+
logger.info(f"🔌 Plugins before hook: {context.command_name}")
|
469
|
+
|
470
|
+
# Add plugins metadata
|
471
|
+
context.metadata["plugins_check_time"] = datetime.now().isoformat()
|
472
|
+
|
473
|
+
|
474
|
+
def plugins_after_hook(context: HookContext) -> None:
|
475
|
+
"""After hook for plugins command."""
|
476
|
+
logger.info(f"🔌 Plugins after hook: {context.command_name}")
|
477
|
+
|
478
|
+
if context.result and hasattr(context.result, 'plugins'):
|
479
|
+
# Add hook information to plugins
|
480
|
+
context.result.plugins["_hooks_plugin"] = {
|
481
|
+
"name": "Advanced Hooks System",
|
482
|
+
"version": "1.0.0",
|
483
|
+
"enabled": True
|
484
|
+
}
|
485
|
+
|
486
|
+
|
487
|
+
def settings_before_hook(context: HookContext) -> None:
|
488
|
+
"""Before hook for settings command."""
|
489
|
+
logger.info(f"🔧 Settings before hook: {context.command_name}")
|
490
|
+
|
491
|
+
# Add settings metadata
|
492
|
+
context.metadata["settings_operation"] = context.params.get("operation", "unknown")
|
493
|
+
context.metadata["settings_time"] = datetime.now().isoformat()
|
494
|
+
|
495
|
+
|
496
|
+
def settings_after_hook(context: HookContext) -> None:
|
497
|
+
"""After hook for settings command."""
|
498
|
+
logger.info(f"🔧 Settings after hook: {context.command_name}")
|
499
|
+
|
500
|
+
if context.result and hasattr(context.result, 'settings'):
|
501
|
+
# Add hook settings
|
502
|
+
context.result.settings["hooks"] = {
|
503
|
+
"enabled": True,
|
504
|
+
"before_hooks": 15,
|
505
|
+
"after_hooks": 15,
|
506
|
+
"global_hooks": 3
|
507
|
+
}
|
508
|
+
|
509
|
+
|
510
|
+
# ============================================================================
|
511
|
+
# CUSTOM COMMAND HOOKS
|
512
|
+
# ============================================================================
|
513
|
+
|
514
|
+
def manual_echo_before_hook(context: HookContext) -> None:
|
515
|
+
"""Before hook for manual echo command."""
|
516
|
+
logger.info(f"📝 Manual echo before hook: {context.command_name}")
|
517
|
+
|
518
|
+
# Add manual registration flag
|
519
|
+
if context.params and "message" in context.params:
|
520
|
+
context.params["_manually_registered"] = True
|
521
|
+
context.params["_hook_processed"] = True
|
522
|
+
|
523
|
+
|
524
|
+
def manual_echo_after_hook(context: HookContext) -> None:
|
525
|
+
"""After hook for manual echo command."""
|
526
|
+
logger.info(f"📝 Manual echo after hook: {context.command_name}")
|
527
|
+
|
528
|
+
if context.result and hasattr(context.result, 'message'):
|
529
|
+
context.result.message = f"[MANUAL] {context.result.message}"
|
530
|
+
|
531
|
+
|
532
|
+
def auto_echo_before_hook(context: HookContext) -> None:
|
533
|
+
"""Before hook for auto echo command."""
|
534
|
+
logger.info(f"🤖 Auto echo before hook: {context.command_name}")
|
535
|
+
|
536
|
+
# Add auto registration flag
|
537
|
+
if context.params and "message" in context.params:
|
538
|
+
context.params["_auto_registered"] = True
|
539
|
+
context.params["_hook_processed"] = True
|
540
|
+
|
541
|
+
|
542
|
+
def auto_echo_after_hook(context: HookContext) -> None:
|
543
|
+
"""After hook for auto echo command."""
|
544
|
+
logger.info(f"🤖 Auto echo after hook: {context.command_name}")
|
545
|
+
|
546
|
+
if context.result and hasattr(context.result, 'message'):
|
547
|
+
context.result.message = f"[AUTO] {context.result.message}"
|
548
|
+
|
549
|
+
|
550
|
+
def auto_info_before_hook(context: HookContext) -> None:
|
551
|
+
"""Before hook for auto info command."""
|
552
|
+
logger.info(f"🤖 Auto info before hook: {context.command_name}")
|
553
|
+
|
554
|
+
# Add auto registration flag
|
555
|
+
if context.params and "topic" in context.params:
|
556
|
+
context.params["_auto_registered"] = True
|
557
|
+
context.params["_hook_processed"] = True
|
558
|
+
|
559
|
+
|
560
|
+
def auto_info_after_hook(context: HookContext) -> None:
|
561
|
+
"""After hook for auto info command."""
|
562
|
+
logger.info(f"🤖 Auto info after hook: {context.command_name}")
|
249
563
|
|
250
|
-
|
564
|
+
if context.result and hasattr(context.result, 'info'):
|
565
|
+
context.result.info["_auto_generated"] = True
|
566
|
+
context.result.info["_hook_enhanced"] = True
|
@@ -0,0 +1,105 @@
|
|
1
|
+
"""
|
2
|
+
Test command for demonstrating dynamic command loading.
|
3
|
+
|
4
|
+
This command is designed to be dynamically loaded and unloaded
|
5
|
+
to test the command discovery mechanism.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import Optional, Dict, Any
|
9
|
+
from mcp_proxy_adapter.commands.base import Command
|
10
|
+
from mcp_proxy_adapter.commands.result import SuccessResult
|
11
|
+
|
12
|
+
|
13
|
+
class TestCommandResult(SuccessResult):
|
14
|
+
"""Result class for test command."""
|
15
|
+
|
16
|
+
def __init__(self, message: str, test_data: Dict[str, Any]):
|
17
|
+
"""
|
18
|
+
Initialize test command result.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
message: Response message
|
22
|
+
test_data: Additional test data
|
23
|
+
"""
|
24
|
+
super().__init__()
|
25
|
+
self.message = message
|
26
|
+
self.test_data = test_data
|
27
|
+
|
28
|
+
def to_dict(self) -> Dict[str, Any]:
|
29
|
+
"""Convert result to dictionary."""
|
30
|
+
return {
|
31
|
+
"message": self.message,
|
32
|
+
"test_data": self.test_data,
|
33
|
+
"command_type": "test_command",
|
34
|
+
"dynamically_loaded": True
|
35
|
+
}
|
36
|
+
|
37
|
+
@classmethod
|
38
|
+
def get_schema(cls) -> Dict[str, Any]:
|
39
|
+
"""Get result schema."""
|
40
|
+
return {
|
41
|
+
"type": "object",
|
42
|
+
"properties": {
|
43
|
+
"message": {"type": "string"},
|
44
|
+
"test_data": {"type": "object"},
|
45
|
+
"command_type": {"type": "string"},
|
46
|
+
"dynamically_loaded": {"type": "boolean"}
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
|
51
|
+
class TestCommand(Command):
|
52
|
+
"""
|
53
|
+
Test command for dynamic loading demonstration.
|
54
|
+
|
55
|
+
This command can be used to test the dynamic command discovery
|
56
|
+
and loading mechanism.
|
57
|
+
"""
|
58
|
+
|
59
|
+
name = "test"
|
60
|
+
result_class = TestCommandResult
|
61
|
+
|
62
|
+
def __init__(self):
|
63
|
+
"""Initialize test command."""
|
64
|
+
super().__init__()
|
65
|
+
|
66
|
+
async def execute(self, message: Optional[str] = None, **kwargs) -> TestCommandResult:
|
67
|
+
"""
|
68
|
+
Execute test command.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
message: Optional test message
|
72
|
+
**kwargs: Additional parameters
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
TestCommandResult with test data
|
76
|
+
"""
|
77
|
+
test_message = message or "Test command executed successfully!"
|
78
|
+
|
79
|
+
test_data = {
|
80
|
+
"timestamp": self._get_timestamp(),
|
81
|
+
"command_name": "test_command",
|
82
|
+
"parameters": kwargs,
|
83
|
+
"status": "success"
|
84
|
+
}
|
85
|
+
|
86
|
+
return TestCommandResult(test_message, test_data)
|
87
|
+
|
88
|
+
@classmethod
|
89
|
+
def get_schema(cls) -> Dict[str, Any]:
|
90
|
+
"""Get command schema."""
|
91
|
+
return {
|
92
|
+
"type": "object",
|
93
|
+
"properties": {
|
94
|
+
"message": {
|
95
|
+
"type": "string",
|
96
|
+
"description": "Test message to display",
|
97
|
+
"default": "Test command executed successfully!"
|
98
|
+
}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
def _get_timestamp(self) -> str:
|
103
|
+
"""Get current timestamp."""
|
104
|
+
from datetime import datetime
|
105
|
+
return datetime.now().isoformat()
|
@@ -0,0 +1,129 @@
|
|
1
|
+
"""
|
2
|
+
Test command for loadable commands testing.
|
3
|
+
|
4
|
+
This command demonstrates the loadable commands functionality.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Any, Dict
|
8
|
+
|
9
|
+
from mcp_proxy_adapter.commands.base import Command
|
10
|
+
from mcp_proxy_adapter.commands.result import SuccessResult
|
11
|
+
|
12
|
+
|
13
|
+
class TestCommandResult:
|
14
|
+
"""
|
15
|
+
Result of test command execution.
|
16
|
+
"""
|
17
|
+
|
18
|
+
def __init__(self, message: str, test_data: Dict[str, Any]):
|
19
|
+
"""
|
20
|
+
Initialize test command result.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
message: Result message
|
24
|
+
test_data: Test data
|
25
|
+
"""
|
26
|
+
self.message = message
|
27
|
+
self.test_data = test_data
|
28
|
+
|
29
|
+
def to_dict(self) -> Dict[str, Any]:
|
30
|
+
"""
|
31
|
+
Convert result to dictionary.
|
32
|
+
|
33
|
+
Returns:
|
34
|
+
Dictionary representation of the result.
|
35
|
+
"""
|
36
|
+
return {
|
37
|
+
"success": True,
|
38
|
+
"message": self.message,
|
39
|
+
"test_data": self.test_data
|
40
|
+
}
|
41
|
+
|
42
|
+
@classmethod
|
43
|
+
def get_schema(cls) -> Dict[str, Any]:
|
44
|
+
"""
|
45
|
+
Get JSON schema for the result.
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
JSON schema dictionary.
|
49
|
+
"""
|
50
|
+
return {
|
51
|
+
"type": "object",
|
52
|
+
"properties": {
|
53
|
+
"success": {
|
54
|
+
"type": "boolean",
|
55
|
+
"description": "Whether command was successful"
|
56
|
+
},
|
57
|
+
"message": {
|
58
|
+
"type": "string",
|
59
|
+
"description": "Result message"
|
60
|
+
},
|
61
|
+
"test_data": {
|
62
|
+
"type": "object",
|
63
|
+
"description": "Test data"
|
64
|
+
}
|
65
|
+
},
|
66
|
+
"required": ["success", "message", "test_data"]
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
class TestCommand(Command):
|
71
|
+
"""
|
72
|
+
Test command for loadable commands testing.
|
73
|
+
"""
|
74
|
+
|
75
|
+
name = "test"
|
76
|
+
result_class = TestCommandResult
|
77
|
+
|
78
|
+
async def execute(self, **kwargs) -> TestCommandResult:
|
79
|
+
"""
|
80
|
+
Execute test command.
|
81
|
+
|
82
|
+
Args:
|
83
|
+
**kwargs: Command parameters
|
84
|
+
|
85
|
+
Returns:
|
86
|
+
TestCommandResult with test information
|
87
|
+
"""
|
88
|
+
# Get parameters
|
89
|
+
test_param = kwargs.get("test_param", "default_value")
|
90
|
+
echo_text = kwargs.get("echo_text", "Hello from loadable command!")
|
91
|
+
|
92
|
+
# Create test data
|
93
|
+
test_data = {
|
94
|
+
"command_type": "loadable",
|
95
|
+
"test_param": test_param,
|
96
|
+
"echo_text": echo_text,
|
97
|
+
"timestamp": "2025-08-12T09:45:00Z",
|
98
|
+
"status": "working"
|
99
|
+
}
|
100
|
+
|
101
|
+
return TestCommandResult(
|
102
|
+
message=f"Test command executed successfully with param: {test_param}",
|
103
|
+
test_data=test_data
|
104
|
+
)
|
105
|
+
|
106
|
+
@classmethod
|
107
|
+
def get_schema(cls) -> Dict[str, Any]:
|
108
|
+
"""
|
109
|
+
Get JSON schema for command parameters.
|
110
|
+
|
111
|
+
Returns:
|
112
|
+
JSON schema dictionary.
|
113
|
+
"""
|
114
|
+
return {
|
115
|
+
"type": "object",
|
116
|
+
"properties": {
|
117
|
+
"test_param": {
|
118
|
+
"type": "string",
|
119
|
+
"description": "Test parameter",
|
120
|
+
"default": "default_value"
|
121
|
+
},
|
122
|
+
"echo_text": {
|
123
|
+
"type": "string",
|
124
|
+
"description": "Text to echo",
|
125
|
+
"default": "Hello from loadable command!"
|
126
|
+
}
|
127
|
+
},
|
128
|
+
"additionalProperties": False
|
129
|
+
}
|