mcp-proxy-adapter 2.1.0__py3-none-any.whl → 2.1.2__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.
- docs/README.md +172 -0
- docs/README_ru.md +172 -0
- docs/architecture.md +251 -0
- docs/architecture_ru.md +343 -0
- docs/command_development.md +250 -0
- docs/command_development_ru.md +593 -0
- docs/deployment.md +251 -0
- docs/deployment_ru.md +1298 -0
- docs/examples.md +254 -0
- docs/examples_ru.md +401 -0
- docs/mcp_proxy_adapter.md +251 -0
- docs/mcp_proxy_adapter_ru.md +405 -0
- docs/quickstart.md +251 -0
- docs/quickstart_ru.md +397 -0
- docs/testing.md +255 -0
- docs/testing_ru.md +469 -0
- docs/validation_ru.md +287 -0
- examples/analyze_config.py +141 -0
- examples/basic_integration.py +161 -0
- examples/docstring_and_schema_example.py +60 -0
- examples/extension_example.py +60 -0
- examples/help_best_practices.py +67 -0
- examples/help_usage.py +64 -0
- examples/mcp_proxy_client.py +131 -0
- examples/mcp_proxy_config.json +175 -0
- examples/openapi_server.py +369 -0
- examples/project_structure_example.py +47 -0
- examples/testing_example.py +53 -0
- mcp_proxy_adapter/__init__.py +17 -0
- mcp_proxy_adapter/adapter.py +697 -0
- mcp_proxy_adapter/models.py +47 -0
- mcp_proxy_adapter/registry.py +439 -0
- mcp_proxy_adapter/schema.py +257 -0
- {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/METADATA +2 -2
- mcp_proxy_adapter-2.1.2.dist-info/RECORD +61 -0
- mcp_proxy_adapter-2.1.2.dist-info/top_level.txt +5 -0
- scripts/code_analyzer/code_analyzer.py +328 -0
- scripts/code_analyzer/register_commands.py +446 -0
- scripts/publish.py +85 -0
- tests/conftest.py +12 -0
- tests/test_adapter.py +529 -0
- tests/test_adapter_coverage.py +274 -0
- tests/test_basic_dispatcher.py +169 -0
- tests/test_command_registry.py +328 -0
- tests/test_examples.py +32 -0
- tests/test_mcp_proxy_adapter.py +568 -0
- tests/test_mcp_proxy_adapter_basic.py +262 -0
- tests/test_part1.py +348 -0
- tests/test_part2.py +524 -0
- tests/test_schema.py +358 -0
- tests/test_simple_adapter.py +251 -0
- adapters/__init__.py +0 -16
- cli/__init__.py +0 -12
- cli/__main__.py +0 -79
- cli/command_runner.py +0 -233
- generators/__init__.py +0 -14
- generators/endpoint_generator.py +0 -172
- generators/openapi_generator.py +0 -254
- generators/rest_api_generator.py +0 -207
- mcp_proxy_adapter-2.1.0.dist-info/RECORD +0 -28
- mcp_proxy_adapter-2.1.0.dist-info/top_level.txt +0 -7
- openapi_schema/__init__.py +0 -38
- openapi_schema/command_registry.py +0 -312
- openapi_schema/rest_schema.py +0 -510
- openapi_schema/rpc_generator.py +0 -307
- openapi_schema/rpc_schema.py +0 -416
- validators/__init__.py +0 -14
- validators/base_validator.py +0 -23
- {analyzers → mcp_proxy_adapter/analyzers}/__init__.py +0 -0
- {analyzers → mcp_proxy_adapter/analyzers}/docstring_analyzer.py +0 -0
- {analyzers → mcp_proxy_adapter/analyzers}/type_analyzer.py +0 -0
- {dispatchers → mcp_proxy_adapter/dispatchers}/__init__.py +0 -0
- {dispatchers → mcp_proxy_adapter/dispatchers}/base_dispatcher.py +0 -0
- {dispatchers → mcp_proxy_adapter/dispatchers}/json_rpc_dispatcher.py +0 -0
- {validators → mcp_proxy_adapter/validators}/docstring_validator.py +0 -0
- {validators → mcp_proxy_adapter/validators}/metadata_validator.py +0 -0
- {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/licenses/LICENSE +0 -0
cli/__main__.py
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python
|
2
|
-
"""
|
3
|
-
Entry point for the command registry CLI interface.
|
4
|
-
|
5
|
-
This module allows running commands from the command line
|
6
|
-
using the command dispatcher.
|
7
|
-
|
8
|
-
Usage:
|
9
|
-
python -m command_registry.cli [command] [args...]
|
10
|
-
"""
|
11
|
-
|
12
|
-
import os
|
13
|
-
import sys
|
14
|
-
import importlib.util
|
15
|
-
from typing import Optional
|
16
|
-
|
17
|
-
from command_registry.cli.command_runner import CommandRunner
|
18
|
-
from command_registry.dispatchers.base_dispatcher import BaseDispatcher
|
19
|
-
from command_registry.dispatchers.command_dispatcher import CommandDispatcher
|
20
|
-
|
21
|
-
|
22
|
-
def find_dispatcher() -> BaseDispatcher:
|
23
|
-
"""
|
24
|
-
Finds and creates command dispatcher.
|
25
|
-
|
26
|
-
Search order:
|
27
|
-
1. Checks DISPATCHER_MODULE environment variable
|
28
|
-
2. Looks for app.py in current directory
|
29
|
-
3. Creates new CommandDispatcher
|
30
|
-
|
31
|
-
Returns:
|
32
|
-
BaseDispatcher: Command dispatcher
|
33
|
-
"""
|
34
|
-
# Check environment variable
|
35
|
-
dispatcher_module = os.environ.get("DISPATCHER_MODULE")
|
36
|
-
if dispatcher_module:
|
37
|
-
try:
|
38
|
-
module_path, attr_name = dispatcher_module.rsplit(":", 1)
|
39
|
-
module = importlib.import_module(module_path)
|
40
|
-
return getattr(module, attr_name)
|
41
|
-
except (ValueError, ImportError, AttributeError) as e:
|
42
|
-
print(f"Failed to load dispatcher from {dispatcher_module}: {e}",
|
43
|
-
file=sys.stderr)
|
44
|
-
|
45
|
-
# Check app.py file
|
46
|
-
app_path = os.path.join(os.getcwd(), "app.py")
|
47
|
-
if os.path.exists(app_path):
|
48
|
-
try:
|
49
|
-
spec = importlib.util.spec_from_file_location("app", app_path)
|
50
|
-
if spec and spec.loader:
|
51
|
-
app = importlib.util.module_from_spec(spec)
|
52
|
-
spec.loader.exec_module(app)
|
53
|
-
|
54
|
-
# Look for dispatcher in module
|
55
|
-
dispatcher = getattr(app, "dispatcher", None)
|
56
|
-
if dispatcher and isinstance(dispatcher, BaseDispatcher):
|
57
|
-
return dispatcher
|
58
|
-
except Exception as e:
|
59
|
-
print(f"Failed to load dispatcher from app.py: {e}",
|
60
|
-
file=sys.stderr)
|
61
|
-
|
62
|
-
# Create new dispatcher if not found
|
63
|
-
return CommandDispatcher()
|
64
|
-
|
65
|
-
|
66
|
-
def main() -> None:
|
67
|
-
"""
|
68
|
-
Main function for running CLI interface.
|
69
|
-
"""
|
70
|
-
# Get dispatcher
|
71
|
-
dispatcher = find_dispatcher()
|
72
|
-
|
73
|
-
# Create and run CommandRunner
|
74
|
-
runner = CommandRunner(dispatcher)
|
75
|
-
runner.run(sys.argv[1:])
|
76
|
-
|
77
|
-
|
78
|
-
if __name__ == "__main__":
|
79
|
-
main()
|
cli/command_runner.py
DELETED
@@ -1,233 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Command line utility for executing commands.
|
3
|
-
|
4
|
-
Provides a command line interface for the command dispatcher,
|
5
|
-
allowing execution of registered commands and getting help information.
|
6
|
-
"""
|
7
|
-
|
8
|
-
import argparse
|
9
|
-
import json
|
10
|
-
import sys
|
11
|
-
from typing import Any, Dict, List, Optional, Sequence
|
12
|
-
|
13
|
-
from command_registry.dispatchers.base_dispatcher import BaseDispatcher
|
14
|
-
|
15
|
-
|
16
|
-
class CommandRunner:
|
17
|
-
"""
|
18
|
-
Command line utility for executing commands.
|
19
|
-
|
20
|
-
Converts command line arguments into dispatcher command calls.
|
21
|
-
Provides ability to get help information about commands.
|
22
|
-
"""
|
23
|
-
|
24
|
-
def __init__(self, dispatcher: BaseDispatcher):
|
25
|
-
"""
|
26
|
-
Initializes CommandRunner.
|
27
|
-
|
28
|
-
Args:
|
29
|
-
dispatcher: Command dispatcher for executing commands
|
30
|
-
"""
|
31
|
-
self.dispatcher = dispatcher
|
32
|
-
|
33
|
-
def build_parser(self) -> argparse.ArgumentParser:
|
34
|
-
"""
|
35
|
-
Creates argument parser based on registered commands.
|
36
|
-
|
37
|
-
Returns:
|
38
|
-
Command line argument parser
|
39
|
-
"""
|
40
|
-
parser = argparse.ArgumentParser(
|
41
|
-
description="Execute commands from command registry",
|
42
|
-
add_help=False, # Disable standard help
|
43
|
-
)
|
44
|
-
|
45
|
-
# Add main arguments
|
46
|
-
parser.add_argument(
|
47
|
-
"command",
|
48
|
-
help="Command name to execute or 'help' to get list of commands",
|
49
|
-
nargs="?",
|
50
|
-
default="help",
|
51
|
-
)
|
52
|
-
|
53
|
-
parser.add_argument(
|
54
|
-
"--help", "-h",
|
55
|
-
action="store_true",
|
56
|
-
help="Show help for specified command",
|
57
|
-
dest="show_help",
|
58
|
-
)
|
59
|
-
|
60
|
-
parser.add_argument(
|
61
|
-
"--json",
|
62
|
-
action="store_true",
|
63
|
-
help="Output result in JSON format",
|
64
|
-
)
|
65
|
-
|
66
|
-
return parser
|
67
|
-
|
68
|
-
def _handle_help_command(self, args: Optional[List[str]] = None) -> None:
|
69
|
-
"""
|
70
|
-
Outputs help information about available commands.
|
71
|
-
|
72
|
-
Args:
|
73
|
-
args: List of arguments, if first argument is command name,
|
74
|
-
outputs help for that command
|
75
|
-
"""
|
76
|
-
if args and len(args) > 0 and args[0] != "help":
|
77
|
-
# Help for specific command
|
78
|
-
command_name = args[0]
|
79
|
-
if command_name not in self.dispatcher.get_valid_commands():
|
80
|
-
print(f"Unknown command: {command_name}", file=sys.stderr)
|
81
|
-
return
|
82
|
-
|
83
|
-
info = self.dispatcher.get_command_info(command_name)
|
84
|
-
|
85
|
-
print(f"\nCommand: {command_name}\n")
|
86
|
-
|
87
|
-
if info.get("description"):
|
88
|
-
print(f"Description: {info['description']}\n")
|
89
|
-
|
90
|
-
if "parameters" in info and info["parameters"]:
|
91
|
-
print("Parameters:")
|
92
|
-
for name, param_info in info["parameters"].items():
|
93
|
-
param_type = param_info.get("type", "any")
|
94
|
-
required = param_info.get("required", False)
|
95
|
-
description = param_info.get("description", "")
|
96
|
-
|
97
|
-
req_str = " (required)" if required else ""
|
98
|
-
print(f" {name} ({param_type}){req_str}")
|
99
|
-
if description:
|
100
|
-
print(f" {description}")
|
101
|
-
print()
|
102
|
-
|
103
|
-
if "returns" in info and info["returns"]:
|
104
|
-
print(f"Returns: {info['returns']}")
|
105
|
-
|
106
|
-
print("\nUsage:")
|
107
|
-
params_str = " ".join(
|
108
|
-
f"--{name}=<value>" for name in info.get("parameters", {})
|
109
|
-
)
|
110
|
-
print(f" python -m command_registry.cli {command_name} {params_str}")
|
111
|
-
else:
|
112
|
-
# General help
|
113
|
-
commands = self.dispatcher.get_commands_info()
|
114
|
-
|
115
|
-
print("\nAvailable commands:\n")
|
116
|
-
for name, info in commands.items():
|
117
|
-
description = info.get("description", "No description")
|
118
|
-
# Show only first line of description for brevity
|
119
|
-
short_desc = description.split("\n")[0]
|
120
|
-
print(f" {name:<20} {short_desc}")
|
121
|
-
|
122
|
-
print("\nTo get detailed information about a command use:")
|
123
|
-
print(" python -m command_registry.cli help <command>")
|
124
|
-
print(" python -m command_registry.cli <command> --help")
|
125
|
-
|
126
|
-
def run(self, args: Sequence[str]) -> None:
|
127
|
-
"""
|
128
|
-
Runs command based on provided arguments.
|
129
|
-
|
130
|
-
Args:
|
131
|
-
args: Command line arguments (without program name)
|
132
|
-
"""
|
133
|
-
parser = self.build_parser()
|
134
|
-
|
135
|
-
# Parse arguments
|
136
|
-
parsed_args, remaining = parser.parse_known_args(args)
|
137
|
-
|
138
|
-
# Handle help command or --help flag
|
139
|
-
if parsed_args.command == "help" or parsed_args.show_help:
|
140
|
-
if parsed_args.command == "help":
|
141
|
-
self._handle_help_command(remaining)
|
142
|
-
else:
|
143
|
-
self._handle_help_command([parsed_args.command])
|
144
|
-
return
|
145
|
-
|
146
|
-
# Check command existence
|
147
|
-
if parsed_args.command not in self.dispatcher.get_valid_commands():
|
148
|
-
print(f"Unknown command: {parsed_args.command}", file=sys.stderr)
|
149
|
-
print("Use 'help' to get list of available commands", file=sys.stderr)
|
150
|
-
sys.exit(1)
|
151
|
-
|
152
|
-
# Convert remaining arguments to command parameters
|
153
|
-
command_params = {}
|
154
|
-
command_info = self.dispatcher.get_command_info(parsed_args.command)
|
155
|
-
expected_params = command_info.get("parameters", {})
|
156
|
-
|
157
|
-
# Parse parameters from remaining arguments
|
158
|
-
i = 0
|
159
|
-
while i < len(remaining):
|
160
|
-
arg = remaining[i]
|
161
|
-
|
162
|
-
# Support --param=value format
|
163
|
-
if arg.startswith("--") and "=" in arg:
|
164
|
-
param_name, value = arg[2:].split("=", 1)
|
165
|
-
command_params[param_name] = self._parse_value(value)
|
166
|
-
i += 1
|
167
|
-
# Support --param value format
|
168
|
-
elif arg.startswith("--"):
|
169
|
-
param_name = arg[2:]
|
170
|
-
if i + 1 < len(remaining) and not remaining[i + 1].startswith("--"):
|
171
|
-
command_params[param_name] = self._parse_value(remaining[i + 1])
|
172
|
-
i += 2
|
173
|
-
else:
|
174
|
-
# Boolean flag
|
175
|
-
command_params[param_name] = True
|
176
|
-
i += 1
|
177
|
-
else:
|
178
|
-
print(f"Unknown argument: {arg}", file=sys.stderr)
|
179
|
-
i += 1
|
180
|
-
|
181
|
-
# Check required parameters
|
182
|
-
for param_name, param_info in expected_params.items():
|
183
|
-
if param_info.get("required", False) and param_name not in command_params:
|
184
|
-
print(f"Missing required parameter: {param_name}", file=sys.stderr)
|
185
|
-
sys.exit(1)
|
186
|
-
|
187
|
-
try:
|
188
|
-
# Execute command
|
189
|
-
result = self.dispatcher.execute(parsed_args.command, **command_params)
|
190
|
-
|
191
|
-
# Output result
|
192
|
-
if parsed_args.json:
|
193
|
-
print(json.dumps(result, ensure_ascii=False, indent=2))
|
194
|
-
elif result is not None:
|
195
|
-
print(result)
|
196
|
-
except Exception as e:
|
197
|
-
print(f"Error executing command: {e}", file=sys.stderr)
|
198
|
-
sys.exit(1)
|
199
|
-
|
200
|
-
def _parse_value(self, value_str: str) -> Any:
|
201
|
-
"""
|
202
|
-
Parses string value into corresponding type.
|
203
|
-
|
204
|
-
Args:
|
205
|
-
value_str: String representation of value
|
206
|
-
|
207
|
-
Returns:
|
208
|
-
Parsed value of corresponding type
|
209
|
-
"""
|
210
|
-
# Boolean values
|
211
|
-
if value_str.lower() in ("true", "yes", "y", "1"):
|
212
|
-
return True
|
213
|
-
if value_str.lower() in ("false", "no", "n", "0"):
|
214
|
-
return False
|
215
|
-
|
216
|
-
# Numbers
|
217
|
-
try:
|
218
|
-
if "." in value_str:
|
219
|
-
return float(value_str)
|
220
|
-
return int(value_str)
|
221
|
-
except ValueError:
|
222
|
-
pass
|
223
|
-
|
224
|
-
# JSON
|
225
|
-
if (value_str.startswith("{") and value_str.endswith("}")) or \
|
226
|
-
(value_str.startswith("[") and value_str.endswith("]")):
|
227
|
-
try:
|
228
|
-
return json.loads(value_str)
|
229
|
-
except json.JSONDecodeError:
|
230
|
-
pass
|
231
|
-
|
232
|
-
# Default - string
|
233
|
-
return value_str
|
generators/__init__.py
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Генераторы API на основе команд и их метаданных.
|
3
|
-
|
4
|
-
Этот модуль содержит классы для автоматической генерации API интерфейсов
|
5
|
-
(REST, OpenAPI и др.) на основе зарегистрированных команд.
|
6
|
-
"""
|
7
|
-
|
8
|
-
from command_registry.generators.rest_api_generator import RestApiGenerator
|
9
|
-
from command_registry.generators.openapi_generator import OpenApiGenerator
|
10
|
-
|
11
|
-
__all__ = [
|
12
|
-
'RestApiGenerator',
|
13
|
-
'OpenApiGenerator',
|
14
|
-
]
|
generators/endpoint_generator.py
DELETED
@@ -1,172 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
REST API endpoint generator based on registered commands.
|
3
|
-
"""
|
4
|
-
from typing import Any, Callable, Dict, List, Optional
|
5
|
-
import inspect
|
6
|
-
import asyncio
|
7
|
-
from fastapi import APIRouter, Depends, Request, HTTPException
|
8
|
-
from pydantic import BaseModel, create_model
|
9
|
-
|
10
|
-
class EndpointGenerator:
|
11
|
-
"""
|
12
|
-
REST API endpoint generator based on registered commands.
|
13
|
-
|
14
|
-
Creates dynamic FastAPI endpoints by automatically generating
|
15
|
-
request and response models based on signatures and docstrings
|
16
|
-
of registered handler functions.
|
17
|
-
"""
|
18
|
-
|
19
|
-
def __init__(self, router: APIRouter, dispatcher: Any):
|
20
|
-
"""
|
21
|
-
Initialize endpoint generator.
|
22
|
-
|
23
|
-
Args:
|
24
|
-
router: FastAPI router for registering endpoints
|
25
|
-
dispatcher: Command dispatcher providing access to registered commands
|
26
|
-
"""
|
27
|
-
self.router = router
|
28
|
-
self.dispatcher = dispatcher
|
29
|
-
self.registered_endpoints = []
|
30
|
-
|
31
|
-
def generate_endpoint(self, command_name: str, handler_func: Callable, metadata: Dict[str, Any]) -> None:
|
32
|
-
"""
|
33
|
-
Generates REST API endpoint for specified command.
|
34
|
-
|
35
|
-
Args:
|
36
|
-
command_name: Command name
|
37
|
-
handler_func: Command handler function
|
38
|
-
metadata: Command metadata from docstring
|
39
|
-
"""
|
40
|
-
# Get function signature
|
41
|
-
sig = inspect.signature(handler_func)
|
42
|
-
|
43
|
-
# Create request model based on function parameters
|
44
|
-
param_fields = {}
|
45
|
-
for name, param in sig.parameters.items():
|
46
|
-
# Skip self parameter
|
47
|
-
if name == 'self':
|
48
|
-
continue
|
49
|
-
|
50
|
-
# Get parameter type and default value
|
51
|
-
param_type = param.annotation if param.annotation != inspect.Parameter.empty else Any
|
52
|
-
default_value = ... if param.default == inspect.Parameter.empty else param.default
|
53
|
-
|
54
|
-
# Add field to model
|
55
|
-
param_fields[name] = (param_type, default_value)
|
56
|
-
|
57
|
-
# Create request model
|
58
|
-
request_model = create_model(
|
59
|
-
f"{command_name.capitalize()}Request",
|
60
|
-
**param_fields
|
61
|
-
)
|
62
|
-
|
63
|
-
# Create endpoint
|
64
|
-
endpoint_path = f"/{command_name}"
|
65
|
-
|
66
|
-
# Define endpoint handler
|
67
|
-
async def endpoint_handler(request_data: request_model):
|
68
|
-
# Call command through dispatcher
|
69
|
-
try:
|
70
|
-
# Get parameters from model
|
71
|
-
params = request_data.__dict__ if hasattr(request_data, "__dict__") else {}
|
72
|
-
|
73
|
-
# Call dispatcher's execute method
|
74
|
-
result = self.dispatcher.execute(command_name, **params)
|
75
|
-
|
76
|
-
# If result is coroutine, await its completion
|
77
|
-
if inspect.iscoroutine(result):
|
78
|
-
result = await result
|
79
|
-
|
80
|
-
return {"success": True, "result": result}
|
81
|
-
except Exception as e:
|
82
|
-
raise HTTPException(status_code=500, detail=str(e))
|
83
|
-
|
84
|
-
# Add documentation from metadata
|
85
|
-
if 'description' in metadata:
|
86
|
-
endpoint_handler.__doc__ = metadata['description']
|
87
|
-
|
88
|
-
# Register endpoint
|
89
|
-
self.router.post(endpoint_path, response_model=None)(endpoint_handler)
|
90
|
-
self.registered_endpoints.append(endpoint_path)
|
91
|
-
|
92
|
-
def generate_all_endpoints(self) -> List[str]:
|
93
|
-
"""
|
94
|
-
Generates endpoints for all registered commands.
|
95
|
-
|
96
|
-
Returns:
|
97
|
-
List[str]: List of created endpoints
|
98
|
-
"""
|
99
|
-
# Create endpoints for all commands
|
100
|
-
commands_info = self.dispatcher.get_commands_info()
|
101
|
-
|
102
|
-
for command_name, command_info in commands_info.items():
|
103
|
-
# Get command handler
|
104
|
-
handler = self.dispatcher._handlers[command_name] if hasattr(self.dispatcher, "_handlers") else None
|
105
|
-
|
106
|
-
# If handler couldn't be obtained, skip command
|
107
|
-
if not handler:
|
108
|
-
continue
|
109
|
-
|
110
|
-
self.generate_endpoint(
|
111
|
-
command_name,
|
112
|
-
handler,
|
113
|
-
command_info
|
114
|
-
)
|
115
|
-
|
116
|
-
# Create help endpoint
|
117
|
-
self.generate_help_endpoint()
|
118
|
-
|
119
|
-
return self.registered_endpoints
|
120
|
-
|
121
|
-
def generate_help_endpoint(self) -> None:
|
122
|
-
"""
|
123
|
-
Creates special /help endpoint that returns information
|
124
|
-
about all available commands and their endpoints.
|
125
|
-
"""
|
126
|
-
async def help_handler(command: Optional[str] = None):
|
127
|
-
if command:
|
128
|
-
# If specific command is specified, return information about it
|
129
|
-
command_info = self.dispatcher.get_command_info(command)
|
130
|
-
if not command_info:
|
131
|
-
return {
|
132
|
-
"success": False,
|
133
|
-
"error": f"Command '{command}' not found",
|
134
|
-
"available_commands": self.dispatcher.get_valid_commands()
|
135
|
-
}
|
136
|
-
|
137
|
-
# Add endpoint URL
|
138
|
-
endpoint_path = f"/{command}"
|
139
|
-
|
140
|
-
return {
|
141
|
-
"success": True,
|
142
|
-
"command": command,
|
143
|
-
"info": command_info,
|
144
|
-
"endpoint": endpoint_path
|
145
|
-
}
|
146
|
-
|
147
|
-
# Otherwise return information about all commands
|
148
|
-
commands_info = {}
|
149
|
-
for cmd in self.dispatcher.get_valid_commands():
|
150
|
-
info = self.dispatcher.get_command_info(cmd)
|
151
|
-
if not info:
|
152
|
-
continue
|
153
|
-
|
154
|
-
endpoint_path = f"/{cmd}"
|
155
|
-
commands_info[cmd] = {
|
156
|
-
"summary": info.get("summary", ""),
|
157
|
-
"description": info.get("description", ""),
|
158
|
-
"endpoint": endpoint_path,
|
159
|
-
"params_count": len(info.get("params", {}))
|
160
|
-
}
|
161
|
-
|
162
|
-
return {
|
163
|
-
"success": True,
|
164
|
-
"commands": commands_info,
|
165
|
-
"total": len(commands_info),
|
166
|
-
"endpoints": self.registered_endpoints,
|
167
|
-
"note": "Use 'command' parameter to get detailed information about a specific command"
|
168
|
-
}
|
169
|
-
|
170
|
-
help_handler.__doc__ = "Get list of all available commands and API endpoints"
|
171
|
-
self.router.get("/help", response_model=None)(help_handler)
|
172
|
-
self.registered_endpoints.append("/help")
|