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
@@ -1,5 +1,20 @@
1
1
  """
2
2
  Module for registering and managing commands.
3
+
4
+ Example: Registering a command instance (for dependency injection)
5
+ ---------------------------------------------------------------
6
+
7
+ .. code-block:: python
8
+
9
+ from mcp_proxy_adapter.commands.command_registry import registry
10
+ from my_commands import MyCommand
11
+
12
+ # Suppose MyCommand requires a service dependency
13
+ service = MyService()
14
+ my_command_instance = MyCommand(service=service)
15
+ registry.register(my_command_instance)
16
+
17
+ # Now, when the command is executed, the same instance (with dependencies) will be used
3
18
  """
4
19
 
5
20
  import importlib
@@ -26,6 +41,7 @@ class CommandRegistry:
26
41
  """
27
42
  self._commands: Dict[str, Type[Command]] = {}
28
43
  self._instances: Dict[str, Command] = {}
44
+ self._custom_commands: Dict[str, Type[Command]] = {} # Custom commands with priority
29
45
 
30
46
  def register(self, command: Union[Type[Command], Command]) -> None:
31
47
  """
@@ -181,7 +197,7 @@ class CommandRegistry:
181
197
  Raises:
182
198
  NotFoundError: If command is not found.
183
199
  """
184
- command_class = self.get_command(command_name)
200
+ command_class = self.get_command_with_priority(command_name)
185
201
 
186
202
  return {
187
203
  "name": command_name,
@@ -204,7 +220,7 @@ class CommandRegistry:
204
220
  Raises:
205
221
  NotFoundError: If command is not found
206
222
  """
207
- command_class = self.get_command(command_name)
223
+ command_class = self.get_command_with_priority(command_name)
208
224
  return command_class.get_metadata()
209
225
 
210
226
  def get_all_metadata(self) -> Dict[str, Dict[str, Any]]:
@@ -215,8 +231,13 @@ class CommandRegistry:
215
231
  Dict with command names as keys and metadata as values
216
232
  """
217
233
  metadata = {}
218
- for name, command_class in self._commands.items():
234
+ # Add custom commands first (they have priority)
235
+ for name, command_class in self._custom_commands.items():
219
236
  metadata[name] = command_class.get_metadata()
237
+ # Add built-in commands (custom commands will override if same name)
238
+ for name, command_class in self._commands.items():
239
+ if name not in self._custom_commands: # Only add if not overridden by custom
240
+ metadata[name] = command_class.get_metadata()
220
241
  return metadata
221
242
 
222
243
  def get_all_commands_info(self) -> Dict[str, Dict[str, Any]]:
@@ -227,8 +248,13 @@ class CommandRegistry:
227
248
  Dictionary with information about all commands.
228
249
  """
229
250
  commands_info = {}
230
- for name in self._commands:
251
+ # Add custom commands first (they have priority)
252
+ for name in self._custom_commands:
231
253
  commands_info[name] = self.get_command_info(name)
254
+ # Add built-in commands (custom commands will override if same name)
255
+ for name in self._commands:
256
+ if name not in self._custom_commands: # Only add if not overridden by custom
257
+ commands_info[name] = self.get_command_info(name)
232
258
  return commands_info
233
259
 
234
260
  def discover_commands(self, package_path: str = "mcp_proxy_adapter.commands") -> None:
@@ -281,13 +307,239 @@ class CommandRegistry:
281
307
  except Exception as e:
282
308
  logger.error(f"Error discovering commands: {e}")
283
309
 
310
+ def register_custom_command(self, command: Union[Type[Command], Command]) -> None:
311
+ """
312
+ Register a custom command with priority over built-in commands.
313
+
314
+ Args:
315
+ command: Command class or instance to register.
316
+
317
+ Raises:
318
+ ValueError: If command with the same name is already registered.
319
+ """
320
+ # Determine if this is a class or an instance
321
+ if isinstance(command, type) and issubclass(command, Command):
322
+ command_class = command
323
+ command_instance = None
324
+ elif isinstance(command, Command):
325
+ command_class = command.__class__
326
+ command_instance = command
327
+ else:
328
+ raise ValueError(f"Invalid command type: {type(command)}. Expected Command class or instance.")
329
+
330
+ # Get command name
331
+ if not hasattr(command_class, "name") or not command_class.name:
332
+ # Use class name if name attribute is not set
333
+ command_name = command_class.__name__.lower()
334
+ if command_name.endswith("command"):
335
+ command_name = command_name[:-7] # Remove "command" suffix
336
+ else:
337
+ command_name = command_class.name
338
+
339
+ if command_name in self._custom_commands:
340
+ logger.debug(f"Custom command '{command_name}' is already registered, skipping")
341
+ raise ValueError(f"Custom command '{command_name}' is already registered")
342
+
343
+ logger.debug(f"Registering custom command: {command_name}")
344
+ self._custom_commands[command_name] = command_class
345
+
346
+ # Store instance if provided
347
+ if command_instance:
348
+ logger.debug(f"Storing custom instance for command: {command_name}")
349
+ self._instances[command_name] = command_instance
350
+
351
+ def unregister_custom_command(self, command_name: str) -> None:
352
+ """
353
+ Remove custom command from registry.
354
+
355
+ Args:
356
+ command_name: Command name to remove.
357
+
358
+ Raises:
359
+ NotFoundError: If command is not found.
360
+ """
361
+ if command_name not in self._custom_commands:
362
+ raise NotFoundError(f"Custom command '{command_name}' not found")
363
+
364
+ logger.debug(f"Unregistering custom command: {command_name}")
365
+ del self._custom_commands[command_name]
366
+
367
+ # Also remove from instances if present
368
+ if command_name in self._instances:
369
+ del self._instances[command_name]
370
+
371
+ def custom_command_exists(self, command_name: str) -> bool:
372
+ """
373
+ Check if custom command exists.
374
+
375
+ Args:
376
+ command_name: Command name to check.
377
+
378
+ Returns:
379
+ True if custom command exists, False otherwise.
380
+ """
381
+ return command_name in self._custom_commands
382
+
383
+ def get_custom_command(self, command_name: str) -> Type[Command]:
384
+ """
385
+ Get custom command class.
386
+
387
+ Args:
388
+ command_name: Command name.
389
+
390
+ Returns:
391
+ Command class.
392
+
393
+ Raises:
394
+ NotFoundError: If command is not found.
395
+ """
396
+ if command_name not in self._custom_commands:
397
+ raise NotFoundError(f"Custom command '{command_name}' not found")
398
+ return self._custom_commands[command_name]
399
+
400
+ def get_all_custom_commands(self) -> Dict[str, Type[Command]]:
401
+ """
402
+ Get all custom commands.
403
+
404
+ Returns:
405
+ Dictionary with custom command names as keys and classes as values.
406
+ """
407
+ return self._custom_commands.copy()
408
+
409
+ def get_priority_command(self, command_name: str) -> Optional[Type[Command]]:
410
+ """
411
+ Get command with priority (custom commands first, then built-in).
412
+
413
+ Args:
414
+ command_name: Command name.
415
+
416
+ Returns:
417
+ Command class if found, None otherwise.
418
+ """
419
+ # First check custom commands
420
+ if command_name in self._custom_commands:
421
+ return self._custom_commands[command_name]
422
+
423
+ # Then check built-in commands
424
+ if command_name in self._commands:
425
+ return self._commands[command_name]
426
+
427
+ return None
428
+
429
+ def command_exists_with_priority(self, command_name: str) -> bool:
430
+ """
431
+ Check if command exists (custom or built-in).
432
+
433
+ Args:
434
+ command_name: Command name to check.
435
+
436
+ Returns:
437
+ True if command exists, False otherwise.
438
+ """
439
+ return (command_name in self._custom_commands or
440
+ command_name in self._commands)
441
+
442
+ def get_command_with_priority(self, command_name: str) -> Type[Command]:
443
+ """
444
+ Get command with priority (custom commands first, then built-in).
445
+
446
+ Args:
447
+ command_name: Command name.
448
+
449
+ Returns:
450
+ Command class.
451
+
452
+ Raises:
453
+ NotFoundError: If command is not found.
454
+ """
455
+ # First check custom commands
456
+ if command_name in self._custom_commands:
457
+ return self._custom_commands[command_name]
458
+
459
+ # Then check built-in commands
460
+ if command_name in self._commands:
461
+ return self._commands[command_name]
462
+
463
+ raise NotFoundError(f"Command '{command_name}' not found")
464
+
284
465
  def clear(self) -> None:
285
466
  """
286
- Clears command registry.
467
+ Clear all registered commands.
287
468
  """
288
- logger.debug("Clearing command registry")
469
+ logger.debug("Clearing all registered commands")
289
470
  self._commands.clear()
290
471
  self._instances.clear()
472
+ self._custom_commands.clear()
473
+
474
+ def reload_config_and_commands(self, package_path: str = "mcp_proxy_adapter.commands") -> Dict[str, Any]:
475
+ """
476
+ Reload configuration and rediscover commands.
477
+
478
+ Args:
479
+ package_path: Path to package with commands.
480
+
481
+ Returns:
482
+ Dictionary with reload information including:
483
+ - config_reloaded: Whether config was reloaded
484
+ - commands_discovered: Number of commands discovered
485
+ - custom_commands_preserved: Number of custom commands preserved
486
+ - total_commands: Total number of commands after reload
487
+ """
488
+ logger.info("🔄 Starting configuration and commands reload...")
489
+
490
+ # Store current custom commands
491
+ custom_commands_backup = self._custom_commands.copy()
492
+
493
+ # Reload configuration
494
+ try:
495
+ from mcp_proxy_adapter.config import config
496
+ config.load_config()
497
+ config_reloaded = True
498
+ logger.info("✅ Configuration reloaded successfully")
499
+ except Exception as e:
500
+ logger.error(f"❌ Failed to reload configuration: {e}")
501
+ config_reloaded = False
502
+
503
+ # Reinitialize logging with new configuration
504
+ try:
505
+ from mcp_proxy_adapter.core.logging import setup_logging
506
+ setup_logging()
507
+ logger.info("✅ Logging reinitialized with new configuration")
508
+ except Exception as e:
509
+ logger.error(f"❌ Failed to reinitialize logging: {e}")
510
+
511
+ # Clear all commands except custom ones
512
+ self._commands.clear()
513
+ self._instances.clear()
514
+
515
+ # Restore custom commands
516
+ self._custom_commands = custom_commands_backup
517
+ custom_commands_preserved = len(custom_commands_backup)
518
+
519
+ # Rediscover commands
520
+ try:
521
+ commands_discovered = self.discover_commands(package_path)
522
+ logger.info(f"✅ Rediscovered {commands_discovered} commands")
523
+ except Exception as e:
524
+ logger.error(f"❌ Failed to rediscover commands: {e}")
525
+ commands_discovered = 0
526
+
527
+ # Get final counts
528
+ total_commands = len(self._commands)
529
+ built_in_commands = total_commands - custom_commands_preserved
530
+ custom_commands = custom_commands_preserved
531
+
532
+ result = {
533
+ "config_reloaded": config_reloaded,
534
+ "commands_discovered": commands_discovered,
535
+ "custom_commands_preserved": custom_commands_preserved,
536
+ "total_commands": total_commands,
537
+ "built_in_commands": built_in_commands,
538
+ "custom_commands": custom_commands
539
+ }
540
+
541
+ logger.info(f"🔄 Reload completed: {result}")
542
+ return result
291
543
 
292
544
 
293
545
  # Global command registry instance
@@ -183,11 +183,10 @@ class HelpCommand(Command):
183
183
  Raises:
184
184
  NotFoundError: If specified command not found
185
185
  """
186
- try:
187
- logger.debug(f"HelpCommand.execute начало: cmdname={cmdname}, kwargs={kwargs}")
186
+ logger.debug(f"HelpCommand.execute начало: cmdname={cmdname}, kwargs={kwargs}")
188
187
 
188
+ try:
189
189
  # Handle case when cmdname is provided
190
- # Important: explicitly check for None or empty string
191
190
  if cmdname is not None and cmdname != "":
192
191
  logger.debug(f"Обработка запроса для конкретной команды: {cmdname}")
193
192
  try:
@@ -196,77 +195,67 @@ class HelpCommand(Command):
196
195
  logger.debug(f"Получены метаданные для команды {cmdname}")
197
196
  return HelpResult(command_info=command_metadata)
198
197
  except NotFoundError:
199
- # If command not found, raise error
200
198
  logger.warning(f"Команда '{cmdname}' не найдена")
201
- raise NotFoundError(f"Command '{cmdname}' not found")
202
- except Exception as e:
203
- logger.error(f"Ошибка при получении метаданных команды {cmdname}: {e}")
204
- logger.debug(f"Трассировка: {traceback.format_exc()}")
205
- # Создаем пустой результат вместо ошибки
206
- return HelpResult(command_info={
207
- "name": cmdname,
208
- "summary": "Command information unavailable",
209
- "description": f"Error retrieving metadata: {str(e)}",
210
- "params": {},
211
- "examples": []
199
+ # Получаем список всех команд
200
+ all_commands = list(registry.get_all_metadata().keys())
201
+ if all_commands:
202
+ example_cmd = all_commands[0]
203
+ example = {
204
+ "command": "help",
205
+ "params": {"cmdname": example_cmd}
206
+ }
207
+ note = f"Use help with an existing command name to get detailed info. For example: help with cmdname '{example_cmd}'. To list all commands: call help without parameters."
208
+ else:
209
+ example = {"command": "help"}
210
+ note = "No commands registered. To list all commands: call help without parameters."
211
+ return HelpResult(commands_info={
212
+ "commands": {},
213
+ "error": f"Command '{cmdname}' not found",
214
+ "example": example,
215
+ "note": note
212
216
  })
213
217
 
214
218
  # Otherwise, return information about all available commands
215
- # and tool metadata
216
219
  logger.debug("Обработка запроса для всех команд")
217
220
 
218
- try:
219
- # Get metadata for all commands
220
- all_metadata = registry.get_all_metadata()
221
- logger.debug(f"Получены метаданные для {len(all_metadata)} команд")
221
+ # Get metadata for all commands
222
+ all_metadata = registry.get_all_metadata()
223
+ logger.debug(f"Получены метаданные для {len(all_metadata)} команд")
222
224
 
223
- # Prepare response format with tool metadata
224
- result = {
225
- "tool_info": {
226
- "name": "MCP-Proxy API Service",
227
- "description": "JSON-RPC API for microservice command execution",
228
- "version": "1.0.0"
229
- },
230
- "help_usage": {
231
- "description": "Get information about commands",
232
- "examples": [
233
- {"command": "help", "description": "List of all available commands"},
234
- {"command": "help", "params": {"cmdname": "command_name"}, "description": "Get detailed information about a specific command"}
235
- ]
236
- },
237
- "commands": {}
238
- }
225
+ # Prepare response format with tool metadata
226
+ result = {
227
+ "tool_info": {
228
+ "name": "MCP-Proxy API Service",
229
+ "description": "JSON-RPC API for microservice command execution",
230
+ "version": "1.0.0"
231
+ },
232
+ "help_usage": {
233
+ "description": "Get information about commands",
234
+ "examples": [
235
+ {"command": "help", "description": "List of all available commands"},
236
+ {"command": "help", "params": {"cmdname": "command_name"}, "description": "Get detailed information about a specific command"}
237
+ ]
238
+ },
239
+ "commands": {}
240
+ }
239
241
 
240
- # Add brief information about commands
241
- for name, metadata in all_metadata.items():
242
- try:
243
- logger.debug(f"Обработка метаданных команды {name}")
244
- # Безопасное получение параметров с проверкой на наличие ключей
245
- result["commands"][name] = {
246
- "summary": metadata.get("summary", ""),
247
- "params_count": len(metadata.get("params", {}))
248
- }
249
- except Exception as e:
250
- logger.error(f"Ошибка при обработке метаданных команды {name}: {e}")
251
- logger.debug(f"Метаданные команды {name}: {metadata}")
252
- # Пропускаем проблемную команду
253
- continue
242
+ # Add brief information about commands
243
+ for name, metadata in all_metadata.items():
244
+ try:
245
+ logger.debug(f"Обработка метаданных команды {name}")
246
+ # Безопасное получение параметров с проверкой на наличие ключей
247
+ result["commands"][name] = {
248
+ "summary": metadata.get("summary", ""),
249
+ "params_count": len(metadata.get("params", {}))
250
+ }
251
+ except Exception as e:
252
+ logger.error(f"Ошибка при обработке метаданных команды {name}: {e}")
253
+ logger.debug(f"Метаданные команды {name}: {metadata}")
254
+ # Пропускаем проблемную команду
255
+ continue
254
256
 
255
- logger.debug(f"HelpCommand.execute завершение: возвращаем результат с {len(result['commands'])} командами")
256
- return HelpResult(commands_info=result)
257
- except Exception as e:
258
- logger.error(f"Ошибка при получении списка команд: {e}")
259
- logger.debug(f"Трассировка: {traceback.format_exc()}")
260
- # Создаем пустой результат вместо ошибки
261
- return HelpResult(commands_info={
262
- "tool_info": {
263
- "name": "MCP-Proxy API Service",
264
- "description": "JSON-RPC API for microservice command execution",
265
- "version": "1.0.0"
266
- },
267
- "commands": {},
268
- "error": str(e)
269
- })
257
+ logger.debug(f"HelpCommand.execute завершение: возвращаем результат с {len(result['commands'])} командами")
258
+ return HelpResult(commands_info=result)
270
259
  except Exception as e:
271
260
  logger.error(f"Неожиданная ошибка в HelpCommand.execute: {e}")
272
261
  logger.debug(f"Трассировка: {traceback.format_exc()}")