mcp-proxy-adapter 6.3.3__py3-none-any.whl → 6.3.5__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 (129) hide show
  1. mcp_proxy_adapter/__init__.py +9 -5
  2. mcp_proxy_adapter/__main__.py +1 -1
  3. mcp_proxy_adapter/api/app.py +227 -176
  4. mcp_proxy_adapter/api/handlers.py +68 -60
  5. mcp_proxy_adapter/api/middleware/__init__.py +7 -5
  6. mcp_proxy_adapter/api/middleware/base.py +19 -16
  7. mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
  8. mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
  9. mcp_proxy_adapter/api/middleware/factory.py +50 -52
  10. mcp_proxy_adapter/api/middleware/logging.py +46 -30
  11. mcp_proxy_adapter/api/middleware/performance.py +19 -16
  12. mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
  13. mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
  14. mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
  15. mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
  16. mcp_proxy_adapter/api/schemas.py +69 -43
  17. mcp_proxy_adapter/api/tool_integration.py +83 -63
  18. mcp_proxy_adapter/api/tools.py +60 -50
  19. mcp_proxy_adapter/commands/__init__.py +15 -6
  20. mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
  21. mcp_proxy_adapter/commands/base.py +108 -112
  22. mcp_proxy_adapter/commands/builtin_commands.py +28 -18
  23. mcp_proxy_adapter/commands/catalog_manager.py +394 -265
  24. mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
  25. mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
  26. mcp_proxy_adapter/commands/command_registry.py +275 -226
  27. mcp_proxy_adapter/commands/config_command.py +48 -33
  28. mcp_proxy_adapter/commands/dependency_container.py +22 -23
  29. mcp_proxy_adapter/commands/dependency_manager.py +65 -56
  30. mcp_proxy_adapter/commands/echo_command.py +15 -15
  31. mcp_proxy_adapter/commands/health_command.py +31 -29
  32. mcp_proxy_adapter/commands/help_command.py +97 -61
  33. mcp_proxy_adapter/commands/hooks.py +65 -49
  34. mcp_proxy_adapter/commands/key_management_command.py +148 -147
  35. mcp_proxy_adapter/commands/load_command.py +58 -40
  36. mcp_proxy_adapter/commands/plugins_command.py +80 -54
  37. mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
  38. mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
  39. mcp_proxy_adapter/commands/reload_command.py +43 -37
  40. mcp_proxy_adapter/commands/result.py +26 -33
  41. mcp_proxy_adapter/commands/role_test_command.py +26 -26
  42. mcp_proxy_adapter/commands/roles_management_command.py +176 -173
  43. mcp_proxy_adapter/commands/security_command.py +134 -122
  44. mcp_proxy_adapter/commands/settings_command.py +47 -56
  45. mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
  46. mcp_proxy_adapter/commands/token_management_command.py +129 -158
  47. mcp_proxy_adapter/commands/transport_management_command.py +41 -36
  48. mcp_proxy_adapter/commands/unload_command.py +42 -37
  49. mcp_proxy_adapter/config.py +36 -35
  50. mcp_proxy_adapter/core/__init__.py +19 -21
  51. mcp_proxy_adapter/core/app_factory.py +30 -9
  52. mcp_proxy_adapter/core/app_runner.py +81 -64
  53. mcp_proxy_adapter/core/auth_validator.py +176 -182
  54. mcp_proxy_adapter/core/certificate_utils.py +469 -426
  55. mcp_proxy_adapter/core/client.py +155 -126
  56. mcp_proxy_adapter/core/client_manager.py +60 -54
  57. mcp_proxy_adapter/core/client_security.py +108 -88
  58. mcp_proxy_adapter/core/config_converter.py +176 -143
  59. mcp_proxy_adapter/core/config_validator.py +12 -4
  60. mcp_proxy_adapter/core/crl_utils.py +21 -7
  61. mcp_proxy_adapter/core/errors.py +64 -20
  62. mcp_proxy_adapter/core/logging.py +34 -29
  63. mcp_proxy_adapter/core/mtls_asgi.py +29 -25
  64. mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
  65. mcp_proxy_adapter/core/protocol_manager.py +154 -104
  66. mcp_proxy_adapter/core/proxy_client.py +202 -144
  67. mcp_proxy_adapter/core/proxy_registration.py +12 -2
  68. mcp_proxy_adapter/core/role_utils.py +139 -125
  69. mcp_proxy_adapter/core/security_adapter.py +88 -77
  70. mcp_proxy_adapter/core/security_factory.py +50 -44
  71. mcp_proxy_adapter/core/security_integration.py +72 -24
  72. mcp_proxy_adapter/core/server_adapter.py +68 -64
  73. mcp_proxy_adapter/core/server_engine.py +71 -53
  74. mcp_proxy_adapter/core/settings.py +68 -58
  75. mcp_proxy_adapter/core/ssl_utils.py +69 -56
  76. mcp_proxy_adapter/core/transport_manager.py +72 -60
  77. mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
  78. mcp_proxy_adapter/core/utils.py +4 -2
  79. mcp_proxy_adapter/custom_openapi.py +107 -99
  80. mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
  81. mcp_proxy_adapter/examples/commands/__init__.py +1 -1
  82. mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
  83. mcp_proxy_adapter/examples/debug_request_state.py +38 -19
  84. mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
  85. mcp_proxy_adapter/examples/demo_client.py +48 -36
  86. mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
  87. mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
  88. mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
  89. mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  90. mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
  91. mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  92. mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
  93. mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
  94. mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
  95. mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
  96. mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
  97. mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
  98. mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
  99. mcp_proxy_adapter/examples/full_application/main.py +27 -2
  100. mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
  101. mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
  102. mcp_proxy_adapter/examples/generate_certificates.py +31 -16
  103. mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
  104. mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
  105. mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
  106. mcp_proxy_adapter/examples/run_example.py +23 -5
  107. mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
  108. mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
  109. mcp_proxy_adapter/examples/run_security_tests.py +103 -41
  110. mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
  111. mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
  112. mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
  113. mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
  114. mcp_proxy_adapter/examples/security_test_client.py +196 -127
  115. mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
  116. mcp_proxy_adapter/examples/test_config.py +19 -4
  117. mcp_proxy_adapter/examples/test_config_generator.py +23 -7
  118. mcp_proxy_adapter/examples/test_examples.py +84 -56
  119. mcp_proxy_adapter/examples/universal_client.py +119 -62
  120. mcp_proxy_adapter/openapi.py +108 -115
  121. mcp_proxy_adapter/utils/config_generator.py +429 -274
  122. mcp_proxy_adapter/version.py +1 -2
  123. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/METADATA +1 -1
  124. mcp_proxy_adapter-6.3.5.dist-info/RECORD +143 -0
  125. mcp_proxy_adapter-6.3.3.dist-info/RECORD +0 -143
  126. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/WHEEL +0 -0
  127. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/entry_points.txt +0 -0
  128. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/licenses/LICENSE +0 -0
  129. {mcp_proxy_adapter-6.3.3.dist-info → mcp_proxy_adapter-6.3.5.dist-info}/top_level.txt +0 -0
@@ -13,11 +13,18 @@ class LoadResult(SuccessResult):
13
13
  """
14
14
  Result of the load command execution.
15
15
  """
16
-
17
- def __init__(self, success: bool, commands_loaded: int, loaded_commands: list, source: str, error: Optional[str] = None):
16
+
17
+ def __init__(
18
+ self,
19
+ success: bool,
20
+ commands_loaded: int,
21
+ loaded_commands: list,
22
+ source: str,
23
+ error: Optional[str] = None,
24
+ ):
18
25
  """
19
26
  Initialize load command result.
20
-
27
+
21
28
  Args:
22
29
  success: Whether loading was successful
23
30
  commands_loaded: Number of commands loaded
@@ -29,22 +36,22 @@ class LoadResult(SuccessResult):
29
36
  "success": success,
30
37
  "commands_loaded": commands_loaded,
31
38
  "loaded_commands": loaded_commands,
32
- "source": source
39
+ "source": source,
33
40
  }
34
41
  if error:
35
42
  data["error"] = error
36
-
43
+
37
44
  message = f"Loaded {commands_loaded} commands from {source}"
38
45
  if error:
39
46
  message = f"Failed to load commands from {source}: {error}"
40
-
47
+
41
48
  super().__init__(data=data, message=message)
42
-
49
+
43
50
  @classmethod
44
51
  def get_schema(cls) -> Dict[str, Any]:
45
52
  """
46
53
  Get JSON schema for result validation.
47
-
54
+
48
55
  Returns:
49
56
  Dict[str, Any]: JSON schema
50
57
  """
@@ -58,74 +65,79 @@ class LoadResult(SuccessResult):
58
65
  "commands_loaded": {"type": "integer"},
59
66
  "loaded_commands": {
60
67
  "type": "array",
61
- "items": {"type": "string"}
68
+ "items": {"type": "string"},
62
69
  },
63
70
  "source": {"type": "string"},
64
- "error": {"type": "string"}
71
+ "error": {"type": "string"},
65
72
  },
66
- "required": ["success", "commands_loaded", "loaded_commands", "source"]
73
+ "required": [
74
+ "success",
75
+ "commands_loaded",
76
+ "loaded_commands",
77
+ "source",
78
+ ],
67
79
  }
68
80
  },
69
- "required": ["data"]
81
+ "required": ["data"],
70
82
  }
71
83
 
72
84
 
73
85
  class LoadCommand(Command):
74
86
  """
75
87
  Command that loads commands from local path or URL.
76
-
88
+
77
89
  This command allows dynamic loading of command modules from either local file system
78
90
  or remote HTTP/HTTPS URLs. The command automatically detects whether the source
79
91
  is a local path or URL and handles the loading accordingly.
80
-
92
+
81
93
  For local paths, the command loads Python modules ending with '_command.py'.
82
94
  For URLs, the command downloads the Python code and loads it as a temporary module.
83
-
95
+
84
96
  The loaded commands are registered in the command registry and become immediately
85
97
  available for execution. Only commands that inherit from the base Command class
86
98
  and are properly structured will be loaded and registered.
87
-
99
+
88
100
  Security considerations:
89
101
  - Local paths are validated for existence and proper naming
90
102
  - URLs are downloaded with timeout protection
91
103
  - Temporary files are automatically cleaned up after loading
92
104
  - Only files ending with '_command.py' are accepted
93
-
105
+
94
106
  Examples:
95
107
  - Load from local file: "./my_command.py"
96
108
  - Load from URL: "https://example.com/remote_command.py"
97
109
  """
98
-
110
+
99
111
  name = "load"
100
112
  result_class = LoadResult
101
-
113
+
102
114
  async def execute(self, source: str, **kwargs) -> LoadResult:
103
115
  """
104
116
  Execute load command.
105
-
117
+
106
118
  Args:
107
119
  source: Source path or URL to load command from
108
120
  **kwargs: Additional parameters
109
-
121
+
110
122
  Returns:
111
123
  LoadResult: Load command result
112
124
  """
113
125
  # Load command from source
114
126
  result = registry.load_command_from_source(source)
115
-
127
+
116
128
  return LoadResult(
117
129
  success=result.get("success", False),
118
130
  commands_loaded=result.get("commands_loaded", 0),
119
131
  loaded_commands=result.get("loaded_commands", []),
120
132
  source=result.get("source", source),
121
- error=result.get("error")
133
+ error=result.get("error"),
122
134
  )
123
-
135
+
124
136
  @classmethod
125
137
  def get_schema(cls) -> Dict[str, Any]:
126
138
  """
127
139
  Get JSON schema for command parameters.
128
-
140
+
129
141
  Returns:
130
142
  Dict[str, Any]: JSON schema
131
143
  """
@@ -137,21 +149,23 @@ class LoadCommand(Command):
137
149
  "description": "Source path or URL to load command from (must end with '_command.py')",
138
150
  "examples": [
139
151
  "./my_command.py",
140
- "https://example.com/remote_command.py"
141
- ]
152
+ "https://example.com/remote_command.py",
153
+ ],
142
154
  }
143
155
  },
144
- "required": ["source"]
156
+ "required": ["source"],
145
157
  }
146
-
158
+
147
159
  @classmethod
148
- def _generate_examples(cls, params: Dict[str, Dict[str, Any]]) -> List[Dict[str, Any]]:
160
+ def _generate_examples(
161
+ cls, params: Dict[str, Dict[str, Any]]
162
+ ) -> List[Dict[str, Any]]:
149
163
  """
150
164
  Generate custom examples for load command.
151
-
165
+
152
166
  Args:
153
167
  params: Information about command parameters
154
-
168
+
155
169
  Returns:
156
170
  List of examples
157
171
  """
@@ -159,18 +173,22 @@ class LoadCommand(Command):
159
173
  {
160
174
  "command": cls.name,
161
175
  "params": {"source": "./custom_command.py"},
162
- "description": "Load a command from local file system"
176
+ "description": "Load a command from local file system",
163
177
  },
164
178
  {
165
179
  "command": cls.name,
166
- "params": {"source": "https://raw.githubusercontent.com/user/repo/main/remote_command.py"},
167
- "description": "Load a command from GitHub raw content"
180
+ "params": {
181
+ "source": "https://raw.githubusercontent.com/user/repo/main/remote_command.py"
182
+ },
183
+ "description": "Load a command from GitHub raw content",
168
184
  },
169
185
  {
170
186
  "command": cls.name,
171
- "params": {"source": "https://example.com/api/commands/test_command.py"},
172
- "description": "Load a command from remote API endpoint"
173
- }
187
+ "params": {
188
+ "source": "https://example.com/api/commands/test_command.py"
189
+ },
190
+ "description": "Load a command from remote API endpoint",
191
+ },
174
192
  ]
175
-
176
- return examples
193
+
194
+ return examples
@@ -14,11 +14,18 @@ class PluginsResult(SuccessResult):
14
14
  """
15
15
  Result of the plugins command execution.
16
16
  """
17
-
18
- def __init__(self, success: bool, plugins_server: str, plugins: list, total_plugins: int, error: Optional[str] = None):
17
+
18
+ def __init__(
19
+ self,
20
+ success: bool,
21
+ plugins_server: str,
22
+ plugins: list,
23
+ total_plugins: int,
24
+ error: Optional[str] = None,
25
+ ):
19
26
  """
20
27
  Initialize plugins command result.
21
-
28
+
22
29
  Args:
23
30
  success: Whether operation was successful
24
31
  plugins_server: URL of the plugins server
@@ -30,22 +37,22 @@ class PluginsResult(SuccessResult):
30
37
  "success": success,
31
38
  "plugins_server": plugins_server,
32
39
  "plugins": plugins,
33
- "total_plugins": total_plugins
40
+ "total_plugins": total_plugins,
34
41
  }
35
42
  if error:
36
43
  data["error"] = error
37
-
44
+
38
45
  message = f"Found {total_plugins} plugins from {plugins_server}"
39
46
  if error:
40
47
  message = f"Failed to load plugins from {plugins_server}: {error}"
41
-
48
+
42
49
  super().__init__(data=data, message=message)
43
-
50
+
44
51
  @classmethod
45
52
  def get_schema(cls) -> Dict[str, Any]:
46
53
  """
47
54
  Get JSON schema for result validation.
48
-
55
+
49
56
  Returns:
50
57
  Dict[str, Any]: JSON schema
51
58
  """
@@ -66,32 +73,37 @@ class PluginsResult(SuccessResult):
66
73
  "description": {"type": "string"},
67
74
  "url": {"type": "string"},
68
75
  "version": {"type": "string"},
69
- "author": {"type": "string"}
70
- }
71
- }
76
+ "author": {"type": "string"},
77
+ },
78
+ },
72
79
  },
73
80
  "total_plugins": {"type": "integer"},
74
- "error": {"type": "string"}
81
+ "error": {"type": "string"},
75
82
  },
76
- "required": ["success", "plugins_server", "plugins", "total_plugins"]
83
+ "required": [
84
+ "success",
85
+ "plugins_server",
86
+ "plugins",
87
+ "total_plugins",
88
+ ],
77
89
  }
78
90
  },
79
- "required": ["data"]
91
+ "required": ["data"],
80
92
  }
81
93
 
82
94
 
83
95
  class PluginsCommand(Command):
84
96
  """
85
97
  Command that reads and displays available plugins from a plugins server.
86
-
98
+
87
99
  This command fetches a JSON file from a configured plugins server URL that contains
88
100
  a list of available plugins. Each plugin in the list typically contains metadata
89
101
  such as name, description, URL, version, and author information.
90
-
102
+
91
103
  The plugins server URL is configured in the system configuration under
92
104
  'commands.plugins_server'. The JSON file should contain an array of plugin objects
93
105
  with the following structure:
94
-
106
+
95
107
  {
96
108
  "plugins": [
97
109
  {
@@ -103,43 +115,43 @@ class PluginsCommand(Command):
103
115
  }
104
116
  ]
105
117
  }
106
-
118
+
107
119
  This command is useful for:
108
120
  - Discovering available plugins without manually browsing the server
109
121
  - Getting metadata about plugins before loading them
110
122
  - Building plugin management interfaces
111
123
  - Checking plugin availability and versions
112
-
124
+
113
125
  The command will return the list of all available plugins along with their
114
126
  metadata, making it easy to choose which plugins to load.
115
127
  """
116
-
128
+
117
129
  name = "plugins"
118
130
  result_class = PluginsResult
119
-
131
+
120
132
  async def execute(self, **kwargs) -> PluginsResult:
121
133
  """
122
134
  Execute plugins command.
123
-
135
+
124
136
  Args:
125
137
  **kwargs: Additional parameters
126
-
138
+
127
139
  Returns:
128
140
  PluginsResult: Plugins command result
129
141
  """
130
142
  try:
131
143
  # Get configuration from the global config instance
132
144
  plugins_server_url = config_instance.get("commands.plugins_server")
133
-
145
+
134
146
  if not plugins_server_url:
135
147
  return PluginsResult(
136
148
  success=False,
137
149
  plugins_server="",
138
150
  plugins=[],
139
151
  total_plugins=0,
140
- error="Plugins server URL not configured"
152
+ error="Plugins server URL not configured",
141
153
  )
142
-
154
+
143
155
  # Import requests if available
144
156
  try:
145
157
  import requests
@@ -149,16 +161,16 @@ class PluginsCommand(Command):
149
161
  plugins_server=plugins_server_url,
150
162
  plugins=[],
151
163
  total_plugins=0,
152
- error="requests library not available"
164
+ error="requests library not available",
153
165
  )
154
-
166
+
155
167
  # Fetch plugins list
156
168
  response = requests.get(plugins_server_url, timeout=30)
157
169
  response.raise_for_status()
158
-
170
+
159
171
  # Parse JSON response
160
172
  plugins_data = response.json()
161
-
173
+
162
174
  # Handle different JSON formats
163
175
  if isinstance(plugins_data, list):
164
176
  # Direct array format
@@ -168,42 +180,48 @@ class PluginsCommand(Command):
168
180
  plugins_list = plugins_data.get("plugins", [])
169
181
  elif "plugin" in plugins_data:
170
182
  # Single plugin format (like from plugins.techsup.od.ua/)
171
- plugins_list = [{
172
- "name": plugins_data.get("plugin", "").replace(".py", ""),
173
- "description": plugins_data.get("descr", ""),
174
- "url": f"{plugins_server_url.rstrip('/')}/{plugins_data.get('plugin', '')}",
175
- "version": "1.0.0",
176
- "author": "Unknown",
177
- "category": plugins_data.get("category", "")
178
- }]
183
+ plugins_list = [
184
+ {
185
+ "name": plugins_data.get("plugin", "").replace(".py", ""),
186
+ "description": plugins_data.get("descr", ""),
187
+ "url": f"{plugins_server_url.rstrip('/')}/{plugins_data.get('plugin', '')}",
188
+ "version": "1.0.0",
189
+ "author": "Unknown",
190
+ "category": plugins_data.get("category", ""),
191
+ }
192
+ ]
179
193
  else:
180
194
  # Unknown format, try to extract any plugin-like data
181
195
  plugins_list = []
182
196
  for key, value in plugins_data.items():
183
- if isinstance(value, dict) and any(k in value for k in ["name", "plugin", "url"]):
197
+ if isinstance(value, dict) and any(
198
+ k in value for k in ["name", "plugin", "url"]
199
+ ):
184
200
  plugins_list.append(value)
185
-
201
+
186
202
  return PluginsResult(
187
203
  success=True,
188
204
  plugins_server=plugins_server_url,
189
205
  plugins=plugins_list,
190
- total_plugins=len(plugins_list)
206
+ total_plugins=len(plugins_list),
191
207
  )
192
-
208
+
193
209
  except Exception as e:
194
210
  return PluginsResult(
195
211
  success=False,
196
- plugins_server=plugins_server_url if 'plugins_server_url' in locals() else "",
212
+ plugins_server=(
213
+ plugins_server_url if "plugins_server_url" in locals() else ""
214
+ ),
197
215
  plugins=[],
198
216
  total_plugins=0,
199
- error=str(e)
217
+ error=str(e),
200
218
  )
201
-
219
+
202
220
  @classmethod
203
221
  def get_metadata(cls) -> Dict[str, Any]:
204
222
  """
205
223
  Get command metadata.
206
-
224
+
207
225
  Returns:
208
226
  Dict[str, Any]: Command metadata
209
227
  """
@@ -213,23 +231,31 @@ class PluginsCommand(Command):
213
231
  "description": cls.__doc__,
214
232
  "parameters": {},
215
233
  "examples": cls._generate_examples({}),
216
- "schema": cls.result_class.get_schema()
234
+ "schema": cls.result_class.get_schema(),
217
235
  }
218
-
236
+
219
237
  @classmethod
220
- def _generate_examples(cls, params: Dict[str, Dict[str, Any]]) -> List[Dict[str, Any]]:
238
+ def _generate_examples(
239
+ cls, params: Dict[str, Dict[str, Any]]
240
+ ) -> List[Dict[str, Any]]:
221
241
  """
222
242
  Generate examples for the command.
223
-
243
+
224
244
  Args:
225
245
  params: Command parameters schema
226
-
246
+
227
247
  Returns:
228
248
  List[Dict[str, Any]]: List of examples
229
249
  """
230
250
  examples = [
231
- {"command": cls.name, "description": "Get list of available plugins from configured server"},
251
+ {
252
+ "command": cls.name,
253
+ "description": "Get list of available plugins from configured server",
254
+ },
232
255
  {"command": cls.name, "description": "Discover plugins without parameters"},
233
- {"command": cls.name, "description": "Check plugin availability and metadata"}
256
+ {
257
+ "command": cls.name,
258
+ "description": "Check plugin availability and metadata",
259
+ },
234
260
  ]
235
- return examples
261
+ return examples