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.
Files changed (78) hide show
  1. docs/README.md +172 -0
  2. docs/README_ru.md +172 -0
  3. docs/architecture.md +251 -0
  4. docs/architecture_ru.md +343 -0
  5. docs/command_development.md +250 -0
  6. docs/command_development_ru.md +593 -0
  7. docs/deployment.md +251 -0
  8. docs/deployment_ru.md +1298 -0
  9. docs/examples.md +254 -0
  10. docs/examples_ru.md +401 -0
  11. docs/mcp_proxy_adapter.md +251 -0
  12. docs/mcp_proxy_adapter_ru.md +405 -0
  13. docs/quickstart.md +251 -0
  14. docs/quickstart_ru.md +397 -0
  15. docs/testing.md +255 -0
  16. docs/testing_ru.md +469 -0
  17. docs/validation_ru.md +287 -0
  18. examples/analyze_config.py +141 -0
  19. examples/basic_integration.py +161 -0
  20. examples/docstring_and_schema_example.py +60 -0
  21. examples/extension_example.py +60 -0
  22. examples/help_best_practices.py +67 -0
  23. examples/help_usage.py +64 -0
  24. examples/mcp_proxy_client.py +131 -0
  25. examples/mcp_proxy_config.json +175 -0
  26. examples/openapi_server.py +369 -0
  27. examples/project_structure_example.py +47 -0
  28. examples/testing_example.py +53 -0
  29. mcp_proxy_adapter/__init__.py +17 -0
  30. mcp_proxy_adapter/adapter.py +697 -0
  31. mcp_proxy_adapter/models.py +47 -0
  32. mcp_proxy_adapter/registry.py +439 -0
  33. mcp_proxy_adapter/schema.py +257 -0
  34. {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/METADATA +2 -2
  35. mcp_proxy_adapter-2.1.2.dist-info/RECORD +61 -0
  36. mcp_proxy_adapter-2.1.2.dist-info/top_level.txt +5 -0
  37. scripts/code_analyzer/code_analyzer.py +328 -0
  38. scripts/code_analyzer/register_commands.py +446 -0
  39. scripts/publish.py +85 -0
  40. tests/conftest.py +12 -0
  41. tests/test_adapter.py +529 -0
  42. tests/test_adapter_coverage.py +274 -0
  43. tests/test_basic_dispatcher.py +169 -0
  44. tests/test_command_registry.py +328 -0
  45. tests/test_examples.py +32 -0
  46. tests/test_mcp_proxy_adapter.py +568 -0
  47. tests/test_mcp_proxy_adapter_basic.py +262 -0
  48. tests/test_part1.py +348 -0
  49. tests/test_part2.py +524 -0
  50. tests/test_schema.py +358 -0
  51. tests/test_simple_adapter.py +251 -0
  52. adapters/__init__.py +0 -16
  53. cli/__init__.py +0 -12
  54. cli/__main__.py +0 -79
  55. cli/command_runner.py +0 -233
  56. generators/__init__.py +0 -14
  57. generators/endpoint_generator.py +0 -172
  58. generators/openapi_generator.py +0 -254
  59. generators/rest_api_generator.py +0 -207
  60. mcp_proxy_adapter-2.1.0.dist-info/RECORD +0 -28
  61. mcp_proxy_adapter-2.1.0.dist-info/top_level.txt +0 -7
  62. openapi_schema/__init__.py +0 -38
  63. openapi_schema/command_registry.py +0 -312
  64. openapi_schema/rest_schema.py +0 -510
  65. openapi_schema/rpc_generator.py +0 -307
  66. openapi_schema/rpc_schema.py +0 -416
  67. validators/__init__.py +0 -14
  68. validators/base_validator.py +0 -23
  69. {analyzers → mcp_proxy_adapter/analyzers}/__init__.py +0 -0
  70. {analyzers → mcp_proxy_adapter/analyzers}/docstring_analyzer.py +0 -0
  71. {analyzers → mcp_proxy_adapter/analyzers}/type_analyzer.py +0 -0
  72. {dispatchers → mcp_proxy_adapter/dispatchers}/__init__.py +0 -0
  73. {dispatchers → mcp_proxy_adapter/dispatchers}/base_dispatcher.py +0 -0
  74. {dispatchers → mcp_proxy_adapter/dispatchers}/json_rpc_dispatcher.py +0 -0
  75. {validators → mcp_proxy_adapter/validators}/docstring_validator.py +0 -0
  76. {validators → mcp_proxy_adapter/validators}/metadata_validator.py +0 -0
  77. {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/WHEEL +0 -0
  78. {mcp_proxy_adapter-2.1.0.dist-info → mcp_proxy_adapter-2.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,312 +0,0 @@
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()