mcp-proxy-adapter 2.1.7__py3-none-any.whl → 2.1.9__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/adapter.py +13 -3
- mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +11 -17
- mcp_proxy_adapter/examples/openapi_server.py +1 -1
- mcp_proxy_adapter/testing_utils.py +112 -0
- {mcp_proxy_adapter-2.1.7.dist-info → mcp_proxy_adapter-2.1.9.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-2.1.7.dist-info → mcp_proxy_adapter-2.1.9.dist-info}/RECORD +9 -8
- {mcp_proxy_adapter-2.1.7.dist-info → mcp_proxy_adapter-2.1.9.dist-info}/WHEEL +1 -1
- {mcp_proxy_adapter-2.1.7.dist-info → mcp_proxy_adapter-2.1.9.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-2.1.7.dist-info → mcp_proxy_adapter-2.1.9.dist-info}/top_level.txt +0 -0
mcp_proxy_adapter/adapter.py
CHANGED
@@ -493,6 +493,13 @@ class MCPProxyAdapter:
|
|
493
493
|
"details": "Request requires 'command', 'method' or 'params' field"
|
494
494
|
}
|
495
495
|
}
|
496
|
+
# Подмена help -> __help
|
497
|
+
if command == "help":
|
498
|
+
command = "__help"
|
499
|
+
# Переименовываем параметр внутри params
|
500
|
+
if "command" in params:
|
501
|
+
params["cmdname"] = params.pop("command")
|
502
|
+
logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
|
496
503
|
|
497
504
|
# Check if command exists
|
498
505
|
if command not in self.registry.dispatcher.get_valid_commands():
|
@@ -501,12 +508,14 @@ class MCPProxyAdapter:
|
|
501
508
|
"error": {
|
502
509
|
"code": 404,
|
503
510
|
"message": f"Unknown command: {command}",
|
504
|
-
"details": f"
|
511
|
+
"details": f"Unknown command: {command}. Available commands: {', '.join(self.registry.dispatcher.get_valid_commands())}"
|
505
512
|
}
|
506
513
|
}
|
507
514
|
|
515
|
+
logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
|
508
516
|
# Check for required parameters
|
509
517
|
command_info = self.registry.dispatcher.get_command_info(command)
|
518
|
+
logger.info(f"[DEBUG] MCP CMD: command_info={command_info}")
|
510
519
|
if command_info and "params" in command_info:
|
511
520
|
missing_params = []
|
512
521
|
for param_name, param_info in command_info["params"].items():
|
@@ -522,7 +531,7 @@ class MCPProxyAdapter:
|
|
522
531
|
"details": f"Command '{command}' requires following parameters: {', '.join(missing_params)}"
|
523
532
|
}
|
524
533
|
}
|
525
|
-
|
534
|
+
logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
|
526
535
|
# Check parameter types
|
527
536
|
type_errors = self._validate_param_types(command, params)
|
528
537
|
if type_errors:
|
@@ -534,9 +543,10 @@ class MCPProxyAdapter:
|
|
534
543
|
"details": "Check parameter types and try again"
|
535
544
|
}
|
536
545
|
}
|
537
|
-
|
546
|
+
logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
|
538
547
|
# Execute the command
|
539
548
|
try:
|
549
|
+
logger.info(f"[DEBUG] MCP CMD: executing command={command}, params={params}")
|
540
550
|
result = self.registry.dispatcher.execute(command, **params)
|
541
551
|
|
542
552
|
# Return result in MCP Proxy format
|
@@ -41,7 +41,7 @@ class JsonRpcDispatcher(BaseDispatcher):
|
|
41
41
|
description="Returns information about available commands",
|
42
42
|
summary="Command help",
|
43
43
|
params={
|
44
|
-
"
|
44
|
+
"cmdname": {
|
45
45
|
"type": "string",
|
46
46
|
"description": "Command name for detailed information",
|
47
47
|
"required": False
|
@@ -157,31 +157,26 @@ class JsonRpcDispatcher(BaseDispatcher):
|
|
157
157
|
def _help_command(self, params: Dict[str, Any] = None) -> Dict[str, Any]:
|
158
158
|
"""
|
159
159
|
Built-in help command for getting command information.
|
160
|
-
|
161
160
|
Args:
|
162
|
-
params: Command parameters
|
163
|
-
|
164
|
-
|
161
|
+
params: Command parameters (dict)
|
162
|
+
cmdname: Command name for detailed information
|
165
163
|
Returns:
|
166
164
|
Dict[str, Any]: Command help information
|
167
165
|
"""
|
168
|
-
if
|
166
|
+
if params is None:
|
169
167
|
params = {}
|
170
|
-
|
171
168
|
# If specific command is specified, return information only about it
|
172
|
-
|
173
|
-
|
174
|
-
if
|
169
|
+
cmdname = params.get("cmdname")
|
170
|
+
if cmdname:
|
171
|
+
if cmdname not in self._metadata:
|
175
172
|
return {
|
176
|
-
"error": f"Command '{
|
173
|
+
"error": f"Command '{cmdname}' not found",
|
177
174
|
"available_commands": list(self._metadata.keys())
|
178
175
|
}
|
179
|
-
|
180
176
|
return {
|
181
|
-
"
|
182
|
-
"info": self._metadata[
|
177
|
+
"cmdname": cmdname,
|
178
|
+
"info": self._metadata[cmdname]
|
183
179
|
}
|
184
|
-
|
185
180
|
# Otherwise return brief information about all commands
|
186
181
|
commands_info = {}
|
187
182
|
for cmd, info in self._metadata.items():
|
@@ -190,9 +185,8 @@ class JsonRpcDispatcher(BaseDispatcher):
|
|
190
185
|
"description": info["description"],
|
191
186
|
"params_count": len(info["params"])
|
192
187
|
}
|
193
|
-
|
194
188
|
return {
|
195
189
|
"commands": commands_info,
|
196
190
|
"total": len(commands_info),
|
197
|
-
"note": "Use the '
|
191
|
+
"note": "Use the 'cmdname' parameter to get detailed information about a specific command"
|
198
192
|
}
|
@@ -26,7 +26,7 @@ from mcp_proxy_adapter.models import JsonRpcRequest, JsonRpcResponse
|
|
26
26
|
|
27
27
|
# Import MockRegistry from tests for example
|
28
28
|
# (in a real project, CommandRegistry would be used)
|
29
|
-
from
|
29
|
+
from mcp_proxy_adapter.testing_utils import MockRegistry
|
30
30
|
|
31
31
|
# Configure logging
|
32
32
|
logging.basicConfig(level=logging.DEBUG)
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
"""
|
3
|
+
Test utilities for MCP Proxy Adapter: mock dispatcher, registry, and OpenAPI generator.
|
4
|
+
Can be used in examples and tests.
|
5
|
+
"""
|
6
|
+
|
7
|
+
def success_command(value: int = 1) -> dict:
|
8
|
+
return {"result": value * 2}
|
9
|
+
|
10
|
+
def error_command() -> None:
|
11
|
+
raise ValueError("Test error")
|
12
|
+
|
13
|
+
def param_command(required_param: str, optional_param: int = 0) -> dict:
|
14
|
+
return {"required": required_param, "optional": optional_param}
|
15
|
+
|
16
|
+
def complex_param_command(array_param: list, object_param: dict, bool_param: bool = True) -> dict:
|
17
|
+
return {
|
18
|
+
"array_length": len(array_param),
|
19
|
+
"object_keys": list(object_param.keys()),
|
20
|
+
"bool_value": bool_param
|
21
|
+
}
|
22
|
+
|
23
|
+
def type_error_command(param: int) -> dict:
|
24
|
+
return {"param": param + 1}
|
25
|
+
|
26
|
+
class MockDispatcher:
|
27
|
+
def __init__(self):
|
28
|
+
self.commands = {
|
29
|
+
"success": success_command,
|
30
|
+
"error": error_command,
|
31
|
+
"param": param_command,
|
32
|
+
"execute": self.execute_from_params
|
33
|
+
}
|
34
|
+
self.commands_info = {
|
35
|
+
"success": {
|
36
|
+
"description": "Successful command",
|
37
|
+
"params": {"value": {"type": "integer", "description": "Input value", "required": False, "default": 1}}
|
38
|
+
},
|
39
|
+
"error": {"description": "Command with error", "params": {}},
|
40
|
+
"param": {
|
41
|
+
"description": "Command with parameters",
|
42
|
+
"params": {
|
43
|
+
"required_param": {"type": "string", "description": "Required parameter", "required": True},
|
44
|
+
"optional_param": {"type": "integer", "description": "Optional parameter", "required": False, "default": 0}
|
45
|
+
}
|
46
|
+
},
|
47
|
+
"execute": {
|
48
|
+
"description": "Universal command for executing other commands",
|
49
|
+
"params": {"query": {"type": "string", "description": "Command or query to execute", "required": False}}
|
50
|
+
},
|
51
|
+
"complex_param": {
|
52
|
+
"description": "Command with complex parameters",
|
53
|
+
"params": {
|
54
|
+
"array_param": {"type": "array", "description": "Array of values", "required": True},
|
55
|
+
"object_param": {"type": "object", "description": "Object", "required": True},
|
56
|
+
"bool_param": {"type": "boolean", "description": "Boolean value", "required": False, "default": True}
|
57
|
+
}
|
58
|
+
},
|
59
|
+
"type_error": {
|
60
|
+
"description": "Command that will raise TypeError",
|
61
|
+
"params": {"param": {"type": "integer", "description": "Integer parameter", "required": True}}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
def execute_from_params(self, **params):
|
66
|
+
if "query" in params and params["query"] in self.commands:
|
67
|
+
command = params.pop("query")
|
68
|
+
return self.execute(command, **params)
|
69
|
+
return {"available_commands": self.get_valid_commands(), "received_params": params}
|
70
|
+
|
71
|
+
def execute(self, command, **params):
|
72
|
+
if command not in self.commands:
|
73
|
+
raise KeyError(f"Unknown command: {command}")
|
74
|
+
return self.commands[command](**params)
|
75
|
+
|
76
|
+
def get_valid_commands(self):
|
77
|
+
return list(self.commands.keys())
|
78
|
+
|
79
|
+
def get_command_info(self, command):
|
80
|
+
return self.commands_info.get(command)
|
81
|
+
|
82
|
+
def get_commands_info(self):
|
83
|
+
return self.commands_info
|
84
|
+
|
85
|
+
class MockRegistry:
|
86
|
+
def __init__(self, use_openapi_generator=False):
|
87
|
+
self.dispatcher = MockDispatcher()
|
88
|
+
self.generators = []
|
89
|
+
self.use_openapi_generator = use_openapi_generator
|
90
|
+
|
91
|
+
def get_commands_info(self):
|
92
|
+
return self.dispatcher.get_commands_info()
|
93
|
+
|
94
|
+
def add_generator(self, generator):
|
95
|
+
self.generators.append(generator)
|
96
|
+
if hasattr(generator, 'set_dispatcher'):
|
97
|
+
generator.set_dispatcher(self.dispatcher)
|
98
|
+
|
99
|
+
class MockOpenApiGenerator:
|
100
|
+
def __init__(self, **kwargs):
|
101
|
+
self.dispatcher = None
|
102
|
+
self.kwargs = kwargs
|
103
|
+
|
104
|
+
def set_dispatcher(self, dispatcher):
|
105
|
+
self.dispatcher = dispatcher
|
106
|
+
|
107
|
+
def generate_schema(self):
|
108
|
+
return {
|
109
|
+
"openapi": "3.0.0",
|
110
|
+
"info": {"title": "Mock API", "version": "1.0.0"},
|
111
|
+
"paths": {}
|
112
|
+
}
|
@@ -1,14 +1,15 @@
|
|
1
1
|
mcp_proxy_adapter/__init__.py,sha256=_6D-TfANWp9zc550M5LUeGPvioFqG1bAl3tZj-gNmJU,463
|
2
|
-
mcp_proxy_adapter/adapter.py,sha256=
|
2
|
+
mcp_proxy_adapter/adapter.py,sha256=XQGhht_lhLH7eaSAgoxl4NdbT1MwMW5mwDrTJMXl8pk,29631
|
3
3
|
mcp_proxy_adapter/models.py,sha256=acqVQBYAojHXeJ1MJyvpMyT6-J6aMxWuZMszn_-RsOU,2338
|
4
4
|
mcp_proxy_adapter/registry.py,sha256=jgC4TKaPbMbAsoxvGp2ToaOE4drD-VfZug7WJbm4IW4,15853
|
5
5
|
mcp_proxy_adapter/schema.py,sha256=HZM0TTQTSi8ha1TEeVevdCyGZOUPoT1soB7Nex0hV50,10947
|
6
|
+
mcp_proxy_adapter/testing_utils.py,sha256=RWjQFNSUtVkeP0qNzp6_jrT6_tub3w_052DrRmvxVk0,4243
|
6
7
|
mcp_proxy_adapter/analyzers/__init__.py,sha256=2rcYZDP-bXq078MQpxP32lAwYYyRhOwAQGBcefBfBzY,368
|
7
8
|
mcp_proxy_adapter/analyzers/docstring_analyzer.py,sha256=T3FLJEo_uChShfiEKRl8GpVoHvh5HiudZkxnj4KixfA,7541
|
8
9
|
mcp_proxy_adapter/analyzers/type_analyzer.py,sha256=6Wac7osKwF03waFSwQ8ZM0Wqn_zAP2D-I4WMEpR0hQM,5230
|
9
10
|
mcp_proxy_adapter/dispatchers/__init__.py,sha256=FWgimgInGphIjCEnvA3-ZExiapUzYAVis2H9C5IWivU,365
|
10
11
|
mcp_proxy_adapter/dispatchers/base_dispatcher.py,sha256=S5_Xri058jAmOWeit1tedB_GMZQ9RLcNcYabA83ZF6k,2288
|
11
|
-
mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py,sha256=
|
12
|
+
mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py,sha256=Iv7Z4GX5Wy6gGNESEYqjLnrPvxPYXa9WJiwaTSKMjg0,6238
|
12
13
|
mcp_proxy_adapter/examples/analyze_config.py,sha256=vog7TNHDw5ZoYhQLbAvZvEoufmQwH54KJzQBJrSq5w4,4283
|
13
14
|
mcp_proxy_adapter/examples/basic_integration.py,sha256=w_oA777YiQt36gzI113KPQ6k45caXbMCqW9hD8sy8zo,4657
|
14
15
|
mcp_proxy_adapter/examples/docstring_and_schema_example.py,sha256=c96L4KF_7yWzffmvd4hyeQuXSdYyYkv7Uvuy0QxgMcQ,1929
|
@@ -16,13 +17,13 @@ mcp_proxy_adapter/examples/extension_example.py,sha256=vnatnFdNTapMpPcQ79Ugitk92
|
|
16
17
|
mcp_proxy_adapter/examples/help_best_practices.py,sha256=wUtZRnAktnpfAc9vAvqSxUquHEr5ewaPDPyc6BoCqdQ,2637
|
17
18
|
mcp_proxy_adapter/examples/help_usage.py,sha256=UOd3HJeYlQpQkAyceGNm66jXX_h-T05pjIGD-b7-Pfg,2568
|
18
19
|
mcp_proxy_adapter/examples/mcp_proxy_client.py,sha256=z4IzFlGigVTQSb8TpcrQ_a0migsmC58LnNwc8wZmTfw,3811
|
19
|
-
mcp_proxy_adapter/examples/openapi_server.py,sha256=
|
20
|
+
mcp_proxy_adapter/examples/openapi_server.py,sha256=MXCr5qifI03oexgdY05SsnbhWCe2_6ebnYOfAdk_Uug,14027
|
20
21
|
mcp_proxy_adapter/examples/project_structure_example.py,sha256=sswTo6FZb1F5juHa0FYG3cgvrh3wfgGfJu2bBy5tCm4,1460
|
21
22
|
mcp_proxy_adapter/examples/testing_example.py,sha256=AB13c4C1bjs1145O-yriwyreeVXtMOlQLzs2BCGmprk,1719
|
22
23
|
mcp_proxy_adapter/validators/docstring_validator.py,sha256=Onpq2iNJ1qF4ejkJJIlBkLROuSNIVALHVmXIgkCpaFI,2934
|
23
24
|
mcp_proxy_adapter/validators/metadata_validator.py,sha256=uCrn38-VYYn89l6f5CC_GoTAHAweaOW2Z6Esro1rtGw,3155
|
24
|
-
mcp_proxy_adapter-2.1.
|
25
|
-
mcp_proxy_adapter-2.1.
|
26
|
-
mcp_proxy_adapter-2.1.
|
27
|
-
mcp_proxy_adapter-2.1.
|
28
|
-
mcp_proxy_adapter-2.1.
|
25
|
+
mcp_proxy_adapter-2.1.9.dist-info/licenses/LICENSE,sha256=OkApFEwdgMCt_mbvUI-eIwKMSTe38K3XnU2DT5ub-wI,1072
|
26
|
+
mcp_proxy_adapter-2.1.9.dist-info/METADATA,sha256=nZ4aznn1akyMf7bPXO3kQb0Az6FiOx2hoCssFuvM05Y,12578
|
27
|
+
mcp_proxy_adapter-2.1.9.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
|
28
|
+
mcp_proxy_adapter-2.1.9.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
|
29
|
+
mcp_proxy_adapter-2.1.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|