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.
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 +703 -354
  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 +12 -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 +101 -18
  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 -68
  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.1.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.1.dist-info/RECORD +0 -110
  99. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/WHEEL +0 -0
  100. {mcp_proxy_adapter-4.1.1.dist-info → mcp_proxy_adapter-6.0.0.dist-info}/licenses/LICENSE +0 -0
  101. {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 HookContext, HookType
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.params}")
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.result}")
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.params}")
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
- "original_params": context.params.copy()
120
+ "bypass_flag": bypass_flag
118
121
  }
119
122
  )
120
123
 
121
- # Set the result and stop standard processing
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" Command intercepted successfully")
128
+ logger.info(f"🚫 Command execution bypassed, result: {mock_result}")
126
129
  else:
127
- # Allow normal execution
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 stop standard processing
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 manager.
229
+ Register advanced hooks with the hooks system.
229
230
 
230
231
  Args:
231
- hooks_manager: The hooks manager instance
232
+ hooks_manager: Hooks manager instance to register hooks with
232
233
  """
233
234
  logger.info("🔧 Registering advanced hooks...")
234
235
 
235
- # Register data transformation hooks
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 interception hooks
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 conditional hooks
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 smart interception hooks
248
- hooks_manager.register_global_before_hook(smart_intercept_hook)
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
- logger.info("✅ Advanced hooks registered successfully")
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
+ }