mcp-proxy-adapter 1.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.
@@ -0,0 +1,262 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-proxy-adapter
3
+ Version: 1.0.0
4
+ Summary: Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.
5
+ Home-page: https://github.com/vasilyvz/mcp-proxy-adapter
6
+ Author: Vasiliy VZ
7
+ Author-email: Vasiliy VZ <vasilyvz@example.com>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/vasilyvz/mcp-proxy-adapter
10
+ Project-URL: Bug Tracker, https://github.com/vasilyvz/mcp-proxy-adapter/issues
11
+ Project-URL: Documentation, https://github.com/vasilyvz/mcp-proxy-adapter/tree/main/docs
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Requires-Python: >=3.9, <4
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: fastapi<1.0.0,>=0.95.0
24
+ Requires-Dist: pydantic<2.0.0,>=1.10.0
25
+ Requires-Dist: uvicorn<1.0.0,>=0.22.0
26
+ Requires-Dist: docstring-parser<1.0.0,>=0.15
27
+ Requires-Dist: typing-extensions<5.0.0,>=4.5.0
28
+ Dynamic: author
29
+ Dynamic: home-page
30
+ Dynamic: license-file
31
+ Dynamic: requires-python
32
+
33
+ # MCP Proxy Adapter
34
+
35
+ Adapter for integrating [Command Registry](docs/README.md) with MCP Proxy, allowing you to use commands as tools for AI models.
36
+
37
+ ## Overview
38
+
39
+ MCP Proxy Adapter transforms commands registered in the Command Registry into a format compatible with MCP Proxy. This enables:
40
+
41
+ 1. Using existing commands as tools for AI models
42
+ 2. Creating a hybrid REST/JSON-RPC API for command execution
43
+ 3. Automatic generation of OpenAPI schemas optimized for MCP Proxy
44
+ 4. Managing tool metadata for better AI system integration
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ pip install mcp-proxy-adapter
50
+ ```
51
+
52
+ ## Quick Start
53
+
54
+ ```python
55
+ from mcp_proxy_adapter import MCPProxyAdapter, CommandRegistry
56
+ from fastapi import FastAPI
57
+
58
+ # Create a command registry instance
59
+ registry = CommandRegistry()
60
+
61
+ # Register commands
62
+ @registry.command
63
+ def calculate_total(prices: list[float], discount: float = 0.0) -> float:
64
+ """
65
+ Calculates the total price with discount.
66
+ Args:
67
+ prices: List of item prices
68
+ discount: Discount percentage (0-100)
69
+ Returns:
70
+ Total price with discount
71
+ """
72
+ subtotal = sum(prices)
73
+ return subtotal * (1 - discount / 100)
74
+
75
+ # Create FastAPI app
76
+ app = FastAPI()
77
+
78
+ # Create and configure MCP Proxy adapter
79
+ adapter = MCPProxyAdapter(registry)
80
+
81
+ # Register endpoints in FastAPI app
82
+ adapter.register_endpoints(app)
83
+
84
+ # Generate and save MCP Proxy config
85
+ adapter.save_config_to_file("mcp_proxy_config.json")
86
+ ```
87
+
88
+ ## Supported Request Formats
89
+
90
+ The adapter supports three request formats for command execution:
91
+
92
+ ### 1. JSON-RPC format
93
+
94
+ ```json
95
+ {
96
+ "jsonrpc": "2.0",
97
+ "method": "command_name",
98
+ "params": {
99
+ "param1": "value1",
100
+ "param2": "value2"
101
+ },
102
+ "id": 1
103
+ }
104
+ ```
105
+
106
+ Example request to `/cmd` endpoint:
107
+
108
+ ```bash
109
+ curl -X POST -H "Content-Type: application/json" -d '{
110
+ "jsonrpc": "2.0",
111
+ "method": "calculate_total",
112
+ "params": {
113
+ "prices": [100, 200, 300],
114
+ "discount": 10
115
+ },
116
+ "id": 1
117
+ }' http://localhost:8000/cmd
118
+ ```
119
+
120
+ Response:
121
+
122
+ ```json
123
+ {
124
+ "jsonrpc": "2.0",
125
+ "result": 540.0,
126
+ "id": 1
127
+ }
128
+ ```
129
+
130
+ ### 2. MCP Proxy format
131
+
132
+ ```json
133
+ {
134
+ "command": "command_name",
135
+ "params": {
136
+ "param1": "value1",
137
+ "param2": "value2"
138
+ }
139
+ }
140
+ ```
141
+
142
+ Example request:
143
+
144
+ ```bash
145
+ curl -X POST -H "Content-Type: application/json" -d '{
146
+ "command": "calculate_total",
147
+ "params": {
148
+ "prices": [100, 200, 300],
149
+ "discount": 10
150
+ }
151
+ }' http://localhost:8000/cmd
152
+ ```
153
+
154
+ Response:
155
+
156
+ ```json
157
+ {
158
+ "result": 540.0
159
+ }
160
+ ```
161
+
162
+ ### 3. Params-only format
163
+
164
+ ```json
165
+ {
166
+ "params": {
167
+ "command": "command_name",
168
+ "param1": "value1",
169
+ "param2": "value2"
170
+ }
171
+ }
172
+ ```
173
+
174
+ or
175
+
176
+ ```json
177
+ {
178
+ "params": {
179
+ "query": "command_name",
180
+ "param1": "value1",
181
+ "param2": "value2"
182
+ }
183
+ }
184
+ ```
185
+
186
+ Example request:
187
+
188
+ ```bash
189
+ curl -X POST -H "Content-Type: application/json" -d '{
190
+ "params": {
191
+ "command": "calculate_total",
192
+ "prices": [100, 200, 300],
193
+ "discount": 10
194
+ }
195
+ }' http://localhost:8000/cmd
196
+ ```
197
+
198
+ Response:
199
+
200
+ ```json
201
+ {
202
+ "result": 540.0
203
+ }
204
+ ```
205
+
206
+ ## Full Example: Integration with FastAPI
207
+
208
+ ```python
209
+ import logging
210
+ from fastapi import FastAPI, APIRouter
211
+ from mcp_proxy_adapter import CommandRegistry, MCPProxyAdapter, configure_logger
212
+
213
+ # Configure logging
214
+ logging.basicConfig(level=logging.INFO)
215
+ project_logger = logging.getLogger("my_project")
216
+
217
+ # Create FastAPI app
218
+ app = FastAPI(title="My API with MCP Proxy Integration")
219
+
220
+ # Create existing API router
221
+ router = APIRouter()
222
+
223
+ @router.get("/items")
224
+ async def get_items():
225
+ """Returns a list of items."""
226
+ return [
227
+ {"id": 1, "name": "Smartphone X", "price": 999.99},
228
+ {"id": 2, "name": "Laptop Y", "price": 1499.99},
229
+ ]
230
+
231
+ app.include_router(router)
232
+
233
+ # Register commands
234
+ registry = CommandRegistry()
235
+
236
+ @registry.command
237
+ def get_discounted_price(price: float, discount: float = 0.0) -> float:
238
+ """
239
+ Returns the price after applying a discount.
240
+ """
241
+ return price * (1 - discount / 100)
242
+
243
+ # Create and register MCP Proxy adapter
244
+ adapter = MCPProxyAdapter(registry)
245
+ adapter.register_endpoints(app)
246
+
247
+ # Save MCP Proxy config
248
+ adapter.save_config_to_file("mcp_proxy_config.json")
249
+ ```
250
+
251
+ ## Features
252
+ - Universal JSON-RPC endpoint for command execution
253
+ - Automatic OpenAPI schema generation and optimization for MCP Proxy
254
+ - Tool metadata for AI models
255
+ - Customizable endpoints and logging
256
+ - Full test coverage and examples
257
+
258
+ ## License
259
+ MIT
260
+
261
+ ## Documentation
262
+ See [docs/](docs/) for detailed guides, architecture, and examples.
@@ -0,0 +1,28 @@
1
+ adapters/__init__.py,sha256=7QraK1j5y29KFSRF4mVxTiWC2Y3IYZLd6GhxUCtjyhg,790
2
+ analyzers/__init__.py,sha256=2rcYZDP-bXq078MQpxP32lAwYYyRhOwAQGBcefBfBzY,368
3
+ analyzers/docstring_analyzer.py,sha256=T3FLJEo_uChShfiEKRl8GpVoHvh5HiudZkxnj4KixfA,7541
4
+ analyzers/type_analyzer.py,sha256=6Wac7osKwF03waFSwQ8ZM0Wqn_zAP2D-I4WMEpR0hQM,5230
5
+ cli/__init__.py,sha256=vJ0VTT7D4KRIOi9nQSgBLub7xywq68i2R1zYQkdA0Uk,416
6
+ cli/__main__.py,sha256=qtjEOB4vkeMASjTppyRFok4IFihRrVOqjk6vLx8OW1g,2400
7
+ cli/command_runner.py,sha256=4d0BZKRG9k4CLk3ZE26jfSxwwrls2e-KsflRoVimfyE,8328
8
+ dispatchers/__init__.py,sha256=FWgimgInGphIjCEnvA3-ZExiapUzYAVis2H9C5IWivU,365
9
+ dispatchers/base_dispatcher.py,sha256=S5_Xri058jAmOWeit1tedB_GMZQ9RLcNcYabA83ZF6k,2288
10
+ dispatchers/json_rpc_dispatcher.py,sha256=ffu1M32E1AdC7IB44mlbV2L56eJQMsp-7fYi_r4rmHc,6331
11
+ generators/__init__.py,sha256=KC8p2HcIBqdyCY1wHnN_c1EfbnPM39YhZLNBDcuv3vA,538
12
+ generators/endpoint_generator.py,sha256=fhEInY3JPwdc5EENesN9VrrONwVZMpsledVpubouJLA,6513
13
+ generators/openapi_generator.py,sha256=0Iqsn0fRr10sTWUK9-MU5MXOXKDHccxKYnmaiQPkKFw,9773
14
+ generators/rest_api_generator.py,sha256=Zg9HVeIuspowXd6aBlyho4UXz-te_Hd4egGzjjIVF48,9159
15
+ mcp_proxy_adapter-1.0.0.dist-info/licenses/LICENSE,sha256=OkApFEwdgMCt_mbvUI-eIwKMSTe38K3XnU2DT5ub-wI,1072
16
+ openapi_schema/__init__.py,sha256=S_lEg-VtlgDdhFxB_u9ZUM1dWKbzW_L_FM-6OCT4EXM,1334
17
+ openapi_schema/command_registry.py,sha256=VqqdsVCcd5neqZ-bsfeKTHeLBeputwUZHxvNxVuvqZs,12075
18
+ openapi_schema/rest_schema.py,sha256=nfF9axtmEA-B-Rw8TCnpmRf6Br3MfQ3TJVx-QHUHoy8,24103
19
+ openapi_schema/rpc_generator.py,sha256=5FGMqjMXcaW0Ej6oey5mgiIxtEKTtA87dc-_kWLWqb0,13640
20
+ openapi_schema/rpc_schema.py,sha256=pebSNt9rKyP2dyHpbjSllak6pQe5AnllReKHhR3UIaI,20162
21
+ validators/__init__.py,sha256=s6zd5oZ3V2pXtzONoH3CiZYLzSVtCoLXpETMFUQfwWY,403
22
+ validators/base_validator.py,sha256=qTEcXnfGqsgKKtc-lnttLiPTuq6vOHfDpZrQ5oP5Fi0,602
23
+ validators/docstring_validator.py,sha256=Onpq2iNJ1qF4ejkJJIlBkLROuSNIVALHVmXIgkCpaFI,2934
24
+ validators/metadata_validator.py,sha256=uCrn38-VYYn89l6f5CC_GoTAHAweaOW2Z6Esro1rtGw,3155
25
+ mcp_proxy_adapter-1.0.0.dist-info/METADATA,sha256=3wKs5p9EEFQCzWRmNySoQny1B4EmoUBFy2HOptUd2R4,5702
26
+ mcp_proxy_adapter-1.0.0.dist-info/WHEEL,sha256=ooBFpIzZCPdw3uqIQsOo4qqbA4ZRPxHnOH7peeONza0,91
27
+ mcp_proxy_adapter-1.0.0.dist-info/top_level.txt,sha256=SlVzE4ry_0xTgDmO2uiaI7ihb9MpR62izN4MH_t1BTU,72
28
+ mcp_proxy_adapter-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-2024 Vasiliy VZ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,7 @@
1
+ adapters
2
+ analyzers
3
+ cli
4
+ dispatchers
5
+ generators
6
+ openapi_schema
7
+ validators
@@ -0,0 +1,38 @@
1
+ """
2
+ Combined OpenAPI schema for REST and RPC API.
3
+ Provides the get_openapi_schema function that returns the complete OpenAPI schema.
4
+ """
5
+ from typing import Dict, Any
6
+
7
+ from .rest_schema import get_rest_schema
8
+ from .rpc_generator import generate_rpc_schema
9
+
10
+ __all__ = ["get_openapi_schema"]
11
+
12
+
13
+ def get_openapi_schema() -> Dict[str, Any]:
14
+ """
15
+ Gets the complete OpenAPI schema that includes both REST and RPC interfaces.
16
+
17
+ Returns:
18
+ Dict[str, Any]: Complete OpenAPI schema
19
+ """
20
+ # Get the base REST schema
21
+ openapi_schema = get_rest_schema()
22
+
23
+ # Generate RPC schema based on REST schema
24
+ rpc_schema = generate_rpc_schema(openapi_schema)
25
+
26
+ # Add /cmd endpoint from RPC schema to the general schema
27
+ openapi_schema["paths"].update(rpc_schema["paths"])
28
+
29
+ # Merge schema components
30
+ for component_type, components in rpc_schema["components"].items():
31
+ if component_type not in openapi_schema["components"]:
32
+ openapi_schema["components"][component_type] = {}
33
+ for component_name, component in components.items():
34
+ # Avoid component duplication
35
+ if component_name not in openapi_schema["components"][component_type]:
36
+ openapi_schema["components"][component_type][component_name] = component
37
+
38
+ return openapi_schema
@@ -0,0 +1,312 @@
1
+ """
2
+ Command registry for automatic OpenAPI schema generation.
3
+ Describes all available API commands, their parameters and response formats.
4
+ """
5
+ from typing import Dict, Any, List, Optional, Type, Union, get_type_hints
6
+ import inspect
7
+ import docstring_parser
8
+ from pydantic import BaseModel, Field, create_model
9
+
10
+ class CommandParameter:
11
+ """Description of a command parameter"""
12
+ def __init__(self, name: str, type_hint: Type, default=None, description: str = None, required: bool = False):
13
+ self.name = name
14
+ self.type_hint = type_hint
15
+ self.default = default
16
+ self.description = description
17
+ self.required = required
18
+
19
+ def to_dict(self) -> Dict[str, Any]:
20
+ """Converts parameter to dictionary for JSON Schema"""
21
+ result = {
22
+ "name": self.name,
23
+ "type": self._get_type_name(),
24
+ "description": self.description or f"Parameter {self.name}",
25
+ "required": self.required
26
+ }
27
+
28
+ if self.default is not None and self.default is not inspect.Parameter.empty:
29
+ result["default"] = self.default
30
+
31
+ return result
32
+
33
+ def _get_type_name(self) -> str:
34
+ """Gets type name for JSON Schema"""
35
+ if self.type_hint == str:
36
+ return "string"
37
+ elif self.type_hint == int:
38
+ return "integer"
39
+ elif self.type_hint == float:
40
+ return "number"
41
+ elif self.type_hint == bool:
42
+ return "boolean"
43
+ elif self.type_hint == list or self.type_hint == List:
44
+ return "array"
45
+ elif self.type_hint == dict or self.type_hint == Dict:
46
+ return "object"
47
+ else:
48
+ return "object"
49
+
50
+
51
+ class CommandInfo:
52
+ """Information about a command"""
53
+ def __init__(self, name: str, handler_func, description: str = None, summary: str = None):
54
+ self.name = name
55
+ self.handler_func = handler_func
56
+ self.description = description or ""
57
+ self.summary = summary or name.replace("_", " ").capitalize()
58
+ self.parameters: List[CommandParameter] = []
59
+ self._parse_parameters()
60
+
61
+ def _parse_parameters(self):
62
+ """Extracts parameter information from function signature"""
63
+ sig = inspect.signature(self.handler_func)
64
+ type_hints = get_type_hints(self.handler_func)
65
+ docstring = docstring_parser.parse(self.handler_func.__doc__ or "")
66
+
67
+ # Create dictionary for finding parameter descriptions in docstring
68
+ param_descriptions = {param.arg_name: param.description for param in docstring.params}
69
+
70
+ for name, param in sig.parameters.items():
71
+ # Ignore self parameter for class methods
72
+ if name == 'self':
73
+ continue
74
+
75
+ # Determine parameter type
76
+ param_type = type_hints.get(name, Any)
77
+
78
+ # Determine if parameter is required
79
+ required = param.default == inspect.Parameter.empty
80
+
81
+ # Add parameter
82
+ self.parameters.append(CommandParameter(
83
+ name=name,
84
+ type_hint=param_type,
85
+ default=None if param.default == inspect.Parameter.empty else param.default,
86
+ description=param_descriptions.get(name),
87
+ required=required
88
+ ))
89
+
90
+ def to_dict(self) -> Dict[str, Any]:
91
+ """Converts command information to dictionary for OpenAPI schema"""
92
+ return {
93
+ "name": self.name,
94
+ "summary": self.summary,
95
+ "description": self.description,
96
+ "parameters": [param.to_dict() for param in self.parameters]
97
+ }
98
+
99
+
100
+ class CommandRegistry:
101
+ """API command registry"""
102
+ def __init__(self):
103
+ self.commands: Dict[str, CommandInfo] = {}
104
+
105
+ def register(self, name: str, handler_func = None, description: str = None, summary: str = None):
106
+ """
107
+ Registers a command in the registry.
108
+ Can be used as a decorator.
109
+
110
+ Args:
111
+ name: Command name
112
+ handler_func: Command handler function
113
+ description: Command description
114
+ summary: Brief command summary
115
+ """
116
+ def decorator(func):
117
+ self.commands[name] = CommandInfo(
118
+ name=name,
119
+ handler_func=func,
120
+ description=description or func.__doc__,
121
+ summary=summary
122
+ )
123
+ return func
124
+
125
+ if handler_func is not None:
126
+ return decorator(handler_func)
127
+ return decorator
128
+
129
+ def get_command(self, name: str) -> Optional[CommandInfo]:
130
+ """Gets information about a command by its name"""
131
+ return self.commands.get(name)
132
+
133
+ def get_all_commands(self) -> List[CommandInfo]:
134
+ """Gets list of all registered commands"""
135
+ return list(self.commands.values())
136
+
137
+ def generate_openapi_components(self) -> Dict[str, Any]:
138
+ """
139
+ Generates OpenAPI schema components based on registered commands.
140
+
141
+ Returns:
142
+ Dict[str, Any]: OpenAPI schema components
143
+ """
144
+ components = {
145
+ "schemas": {}
146
+ }
147
+
148
+ # Add common schemas for CommandRequest and JsonRpcResponse
149
+ components["schemas"]["CommandRequest"] = {
150
+ "type": "object",
151
+ "required": ["command", "jsonrpc"],
152
+ "properties": {
153
+ "jsonrpc": {
154
+ "type": "string",
155
+ "description": "JSON-RPC protocol version",
156
+ "enum": ["2.0"],
157
+ "default": "2.0"
158
+ },
159
+ "id": {
160
+ "type": ["string", "number", "null"],
161
+ "description": "Request identifier, used to match requests and responses"
162
+ },
163
+ "command": {
164
+ "type": "string",
165
+ "title": "Command",
166
+ "description": "Command name to execute",
167
+ "enum": list(self.commands.keys())
168
+ },
169
+ "params": {
170
+ "title": "Params",
171
+ "description": "Command parameters",
172
+ "oneOf": []
173
+ }
174
+ }
175
+ }
176
+
177
+ components["schemas"]["JsonRpcResponse"] = {
178
+ "type": "object",
179
+ "required": ["jsonrpc", "success"],
180
+ "properties": {
181
+ "jsonrpc": {
182
+ "type": "string",
183
+ "description": "JSON-RPC protocol version",
184
+ "enum": ["2.0"],
185
+ "default": "2.0"
186
+ },
187
+ "success": {
188
+ "type": "boolean",
189
+ "description": "Operation success indicator",
190
+ "default": False
191
+ },
192
+ "result": {
193
+ "description": "Operation result. Present only on successful execution (success=True). Result format depends on the executed command."
194
+ },
195
+ "error": {
196
+ "description": "Error information. Present only when error occurs (success=false).",
197
+ "type": "object",
198
+ "required": ["code", "message"],
199
+ "properties": {
200
+ "code": {
201
+ "type": "integer",
202
+ "description": "Error code (internal code, not HTTP status)",
203
+ "example": 400
204
+ },
205
+ "message": {
206
+ "type": "string",
207
+ "description": "Error message description",
208
+ "example": "Record does not exist: ID 12345"
209
+ }
210
+ }
211
+ },
212
+ "id": {
213
+ "type": ["string", "number", "null"],
214
+ "description": "Request identifier (if specified in request)"
215
+ }
216
+ },
217
+ "example": {
218
+ "jsonrpc": "2.0",
219
+ "success": True,
220
+ "result": {"id": "550e8400-e29b-41d4-a716-446655440000"},
221
+ "id": "request-1"
222
+ }
223
+ }
224
+
225
+ # Create schemas for each command's parameters
226
+ for command_name, command_info in self.commands.items():
227
+ param_schema_name = f"{command_name.title().replace('_', '')}Params"
228
+
229
+ # Create command parameter schema
230
+ param_schema = {
231
+ "type": "object",
232
+ "title": param_schema_name,
233
+ "description": f"Parameters for command {command_name}",
234
+ "properties": {},
235
+ "required": []
236
+ }
237
+
238
+ # Add properties for each parameter
239
+ for param in command_info.parameters:
240
+ param_type = param._get_type_name()
241
+ param_schema["properties"][param.name] = {
242
+ "type": param_type,
243
+ "description": param.description or f"Parameter {param.name}"
244
+ }
245
+
246
+ if param.default is not None and param.default is not inspect.Parameter.empty:
247
+ param_schema["properties"][param.name]["default"] = param.default
248
+
249
+ if param.required:
250
+ param_schema["required"].append(param.name)
251
+
252
+ # Add parameter schema to components
253
+ components["schemas"][param_schema_name] = param_schema
254
+
255
+ # Add reference to parameter schema in oneOf list of CommandRequest
256
+ components["schemas"]["CommandRequest"]["properties"]["params"]["oneOf"].append({
257
+ "$ref": f"#/components/schemas/{param_schema_name}"
258
+ })
259
+
260
+ # Add null as possible value for parameters
261
+ components["schemas"]["CommandRequest"]["properties"]["params"]["oneOf"].append({
262
+ "type": "null"
263
+ })
264
+
265
+ return components
266
+
267
+ def generate_examples(self) -> Dict[str, Any]:
268
+ """
269
+ Generates command usage examples for OpenAPI schema.
270
+
271
+ Returns:
272
+ Dict[str, Any]: Command usage examples
273
+ """
274
+ examples = {}
275
+
276
+ for command_name, command_info in self.commands.items():
277
+ # Create base request example
278
+ example = {
279
+ "summary": command_info.summary,
280
+ "value": {
281
+ "jsonrpc": "2.0",
282
+ "command": command_name,
283
+ "params": {},
284
+ "id": command_name
285
+ }
286
+ }
287
+
288
+ # Fill example with default parameters or examples
289
+ for param in command_info.parameters:
290
+ if param.default is not None and param.default is not inspect.Parameter.empty:
291
+ example["value"]["params"][param.name] = param.default
292
+ elif param.type_hint == str:
293
+ example["value"]["params"][param.name] = f"example_{param.name}"
294
+ elif param.type_hint == int:
295
+ example["value"]["params"][param.name] = 1
296
+ elif param.type_hint == float:
297
+ example["value"]["params"][param.name] = 1.0
298
+ elif param.type_hint == bool:
299
+ example["value"]["params"][param.name] = True
300
+ elif param.type_hint == list or param.type_hint == List:
301
+ example["value"]["params"][param.name] = []
302
+ elif param.type_hint == dict or param.type_hint == Dict:
303
+ example["value"]["params"][param.name] = {}
304
+
305
+ # Add example to examples dictionary
306
+ examples[f"{command_name}_example"] = example
307
+
308
+ return examples
309
+
310
+
311
+ # Create global command registry instance
312
+ registry = CommandRegistry()