mcp-proxy-adapter 6.3.4__py3-none-any.whl → 6.3.6__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/__init__.py +9 -5
- mcp_proxy_adapter/__main__.py +1 -1
- mcp_proxy_adapter/api/app.py +227 -176
- mcp_proxy_adapter/api/handlers.py +68 -60
- mcp_proxy_adapter/api/middleware/__init__.py +7 -5
- mcp_proxy_adapter/api/middleware/base.py +19 -16
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +44 -34
- mcp_proxy_adapter/api/middleware/error_handling.py +57 -67
- mcp_proxy_adapter/api/middleware/factory.py +50 -52
- mcp_proxy_adapter/api/middleware/logging.py +46 -30
- mcp_proxy_adapter/api/middleware/performance.py +19 -16
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +80 -50
- mcp_proxy_adapter/api/middleware/transport_middleware.py +26 -24
- mcp_proxy_adapter/api/middleware/unified_security.py +70 -51
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +43 -34
- mcp_proxy_adapter/api/schemas.py +69 -43
- mcp_proxy_adapter/api/tool_integration.py +83 -63
- mcp_proxy_adapter/api/tools.py +60 -50
- mcp_proxy_adapter/commands/__init__.py +15 -6
- mcp_proxy_adapter/commands/auth_validation_command.py +107 -110
- mcp_proxy_adapter/commands/base.py +108 -112
- mcp_proxy_adapter/commands/builtin_commands.py +28 -18
- mcp_proxy_adapter/commands/catalog_manager.py +394 -265
- mcp_proxy_adapter/commands/cert_monitor_command.py +222 -204
- mcp_proxy_adapter/commands/certificate_management_command.py +210 -213
- mcp_proxy_adapter/commands/command_registry.py +275 -226
- mcp_proxy_adapter/commands/config_command.py +48 -33
- mcp_proxy_adapter/commands/dependency_container.py +22 -23
- mcp_proxy_adapter/commands/dependency_manager.py +65 -56
- mcp_proxy_adapter/commands/echo_command.py +15 -15
- mcp_proxy_adapter/commands/health_command.py +31 -29
- mcp_proxy_adapter/commands/help_command.py +97 -61
- mcp_proxy_adapter/commands/hooks.py +65 -49
- mcp_proxy_adapter/commands/key_management_command.py +148 -147
- mcp_proxy_adapter/commands/load_command.py +58 -40
- mcp_proxy_adapter/commands/plugins_command.py +80 -54
- mcp_proxy_adapter/commands/protocol_management_command.py +60 -48
- mcp_proxy_adapter/commands/proxy_registration_command.py +107 -115
- mcp_proxy_adapter/commands/reload_command.py +43 -37
- mcp_proxy_adapter/commands/result.py +26 -33
- mcp_proxy_adapter/commands/role_test_command.py +26 -26
- mcp_proxy_adapter/commands/roles_management_command.py +176 -173
- mcp_proxy_adapter/commands/security_command.py +134 -122
- mcp_proxy_adapter/commands/settings_command.py +47 -56
- mcp_proxy_adapter/commands/ssl_setup_command.py +109 -129
- mcp_proxy_adapter/commands/token_management_command.py +129 -158
- mcp_proxy_adapter/commands/transport_management_command.py +41 -36
- mcp_proxy_adapter/commands/unload_command.py +42 -37
- mcp_proxy_adapter/config.py +36 -35
- mcp_proxy_adapter/core/__init__.py +19 -21
- mcp_proxy_adapter/core/app_factory.py +30 -9
- mcp_proxy_adapter/core/app_runner.py +81 -64
- mcp_proxy_adapter/core/auth_validator.py +176 -182
- mcp_proxy_adapter/core/certificate_utils.py +469 -426
- mcp_proxy_adapter/core/client.py +155 -126
- mcp_proxy_adapter/core/client_manager.py +60 -54
- mcp_proxy_adapter/core/client_security.py +120 -91
- mcp_proxy_adapter/core/config_converter.py +176 -143
- mcp_proxy_adapter/core/config_validator.py +12 -4
- mcp_proxy_adapter/core/crl_utils.py +21 -7
- mcp_proxy_adapter/core/errors.py +64 -20
- mcp_proxy_adapter/core/logging.py +34 -29
- mcp_proxy_adapter/core/mtls_asgi.py +29 -25
- mcp_proxy_adapter/core/mtls_asgi_app.py +66 -54
- mcp_proxy_adapter/core/protocol_manager.py +154 -104
- mcp_proxy_adapter/core/proxy_client.py +202 -144
- mcp_proxy_adapter/core/proxy_registration.py +7 -3
- mcp_proxy_adapter/core/role_utils.py +139 -125
- mcp_proxy_adapter/core/security_adapter.py +88 -77
- mcp_proxy_adapter/core/security_factory.py +50 -44
- mcp_proxy_adapter/core/security_integration.py +72 -24
- mcp_proxy_adapter/core/server_adapter.py +68 -64
- mcp_proxy_adapter/core/server_engine.py +71 -53
- mcp_proxy_adapter/core/settings.py +68 -58
- mcp_proxy_adapter/core/ssl_utils.py +69 -56
- mcp_proxy_adapter/core/transport_manager.py +72 -60
- mcp_proxy_adapter/core/unified_config_adapter.py +201 -150
- mcp_proxy_adapter/core/utils.py +4 -2
- mcp_proxy_adapter/custom_openapi.py +107 -99
- mcp_proxy_adapter/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/commands/__init__.py +1 -1
- mcp_proxy_adapter/examples/create_certificates_simple.py +182 -71
- mcp_proxy_adapter/examples/debug_request_state.py +38 -19
- mcp_proxy_adapter/examples/debug_role_chain.py +53 -20
- mcp_proxy_adapter/examples/demo_client.py +48 -36
- mcp_proxy_adapter/examples/examples/basic_framework/main.py +9 -2
- mcp_proxy_adapter/examples/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/full_application/__init__.py +1 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +22 -10
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +24 -17
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +16 -3
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +13 -3
- mcp_proxy_adapter/examples/full_application/main.py +27 -2
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +48 -14
- mcp_proxy_adapter/examples/generate_all_certificates.py +198 -73
- mcp_proxy_adapter/examples/generate_certificates.py +31 -16
- mcp_proxy_adapter/examples/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/generate_test_configs.py +68 -91
- mcp_proxy_adapter/examples/proxy_registration_example.py +76 -75
- mcp_proxy_adapter/examples/run_example.py +23 -5
- mcp_proxy_adapter/examples/run_full_test_suite.py +109 -71
- mcp_proxy_adapter/examples/run_proxy_server.py +22 -9
- mcp_proxy_adapter/examples/run_security_tests.py +103 -41
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +72 -36
- mcp_proxy_adapter/examples/scripts/config_generator.py +288 -187
- mcp_proxy_adapter/examples/scripts/create_certificates_simple.py +185 -72
- mcp_proxy_adapter/examples/scripts/generate_certificates_and_tokens.py +220 -74
- mcp_proxy_adapter/examples/security_test_client.py +196 -127
- mcp_proxy_adapter/examples/setup_test_environment.py +17 -29
- mcp_proxy_adapter/examples/test_config.py +19 -4
- mcp_proxy_adapter/examples/test_config_generator.py +23 -7
- mcp_proxy_adapter/examples/test_examples.py +84 -56
- mcp_proxy_adapter/examples/universal_client.py +119 -62
- mcp_proxy_adapter/openapi.py +108 -115
- mcp_proxy_adapter/utils/config_generator.py +429 -274
- mcp_proxy_adapter/version.py +1 -2
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-6.3.6.dist-info/RECORD +144 -0
- mcp_proxy_adapter-6.3.6.dist-info/top_level.txt +2 -0
- mcp_proxy_adapter_issue_package/demonstrate_issue.py +178 -0
- mcp_proxy_adapter-6.3.4.dist-info/RECORD +0 -143
- mcp_proxy_adapter-6.3.4.dist-info/top_level.txt +0 -1
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/entry_points.txt +0 -0
- {mcp_proxy_adapter-6.3.4.dist-info → mcp_proxy_adapter-6.3.6.dist-info}/licenses/LICENSE +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__(
|
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": [
|
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(
|
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": {
|
167
|
-
|
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": {
|
172
|
-
|
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__(
|
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": [
|
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
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
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(
|
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=
|
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(
|
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
|
-
{
|
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
|
-
{
|
256
|
+
{
|
257
|
+
"command": cls.name,
|
258
|
+
"description": "Check plugin availability and metadata",
|
259
|
+
},
|
234
260
|
]
|
235
|
-
return examples
|
261
|
+
return examples
|