mcp-proxy-adapter 2.1.9__tar.gz → 2.1.10__tar.gz

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 (50) hide show
  1. {mcp_proxy_adapter-2.1.9/mcp_proxy_adapter.egg-info → mcp_proxy_adapter-2.1.10}/PKG-INFO +1 -1
  2. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/adapter.py +3 -13
  3. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +17 -11
  4. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/help_best_practices.py +2 -2
  5. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/help_usage.py +2 -2
  6. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10/mcp_proxy_adapter.egg-info}/PKG-INFO +1 -1
  7. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/pyproject.toml +1 -1
  8. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/setup.py +1 -1
  9. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_adapter.py +6 -102
  10. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_examples.py +1 -1
  11. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/LICENSE +0 -0
  12. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/MANIFEST.in +0 -0
  13. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/README.md +0 -0
  14. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/code_index.yaml +0 -0
  15. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/__init__.py +0 -0
  16. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/analyzers/__init__.py +0 -0
  17. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/analyzers/docstring_analyzer.py +0 -0
  18. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/analyzers/type_analyzer.py +0 -0
  19. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/dispatchers/__init__.py +0 -0
  20. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/dispatchers/base_dispatcher.py +0 -0
  21. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/analyze_config.py +0 -0
  22. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/basic_integration.py +0 -0
  23. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/docstring_and_schema_example.py +0 -0
  24. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/extension_example.py +0 -0
  25. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/mcp_proxy_client.py +0 -0
  26. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/openapi_server.py +0 -0
  27. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/project_structure_example.py +0 -0
  28. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/examples/testing_example.py +0 -0
  29. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/models.py +0 -0
  30. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/registry.py +0 -0
  31. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/schema.py +0 -0
  32. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/testing_utils.py +0 -0
  33. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/validators/docstring_validator.py +0 -0
  34. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter/validators/metadata_validator.py +0 -0
  35. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter.egg-info/SOURCES.txt +0 -0
  36. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter.egg-info/dependency_links.txt +0 -0
  37. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter.egg-info/requires.txt +0 -0
  38. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/mcp_proxy_adapter.egg-info/top_level.txt +0 -0
  39. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/requirements.txt +0 -0
  40. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/setup.cfg +0 -0
  41. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/conftest.py +0 -0
  42. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_adapter_coverage.py +0 -0
  43. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_basic_dispatcher.py +0 -0
  44. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_command_registry.py +0 -0
  45. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_mcp_proxy_adapter.py +0 -0
  46. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_mcp_proxy_adapter_basic.py +0 -0
  47. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_part1.py +0 -0
  48. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_part2.py +0 -0
  49. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_schema.py +0 -0
  50. {mcp_proxy_adapter-2.1.9 → mcp_proxy_adapter-2.1.10}/tests/test_simple_adapter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 2.1.9
3
+ Version: 2.1.10
4
4
  Summary: Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.
5
5
  Home-page: https://github.com/vasilyvz/mcp-proxy-adapter
6
6
  Author: Vasiliy VZ
@@ -493,13 +493,6 @@ 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}")
503
496
 
504
497
  # Check if command exists
505
498
  if command not in self.registry.dispatcher.get_valid_commands():
@@ -508,14 +501,12 @@ class MCPProxyAdapter:
508
501
  "error": {
509
502
  "code": 404,
510
503
  "message": f"Unknown command: {command}",
511
- "details": f"Unknown command: {command}. Available commands: {', '.join(self.registry.dispatcher.get_valid_commands())}"
504
+ "details": f"Command '{command}' not found in registry. Available commands: {', '.join(self.registry.dispatcher.get_valid_commands())}"
512
505
  }
513
506
  }
514
507
 
515
- logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
516
508
  # Check for required parameters
517
509
  command_info = self.registry.dispatcher.get_command_info(command)
518
- logger.info(f"[DEBUG] MCP CMD: command_info={command_info}")
519
510
  if command_info and "params" in command_info:
520
511
  missing_params = []
521
512
  for param_name, param_info in command_info["params"].items():
@@ -531,7 +522,7 @@ class MCPProxyAdapter:
531
522
  "details": f"Command '{command}' requires following parameters: {', '.join(missing_params)}"
532
523
  }
533
524
  }
534
- logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
525
+
535
526
  # Check parameter types
536
527
  type_errors = self._validate_param_types(command, params)
537
528
  if type_errors:
@@ -543,10 +534,9 @@ class MCPProxyAdapter:
543
534
  "details": "Check parameter types and try again"
544
535
  }
545
536
  }
546
- logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
537
+
547
538
  # Execute the command
548
539
  try:
549
- logger.info(f"[DEBUG] MCP CMD: executing command={command}, params={params}")
550
540
  result = self.registry.dispatcher.execute(command, **params)
551
541
 
552
542
  # 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
- "cmdname": {
44
+ "command": {
45
45
  "type": "string",
46
46
  "description": "Command name for detailed information",
47
47
  "required": False
@@ -157,26 +157,31 @@ 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
+
160
161
  Args:
161
- params: Command parameters (dict)
162
- cmdname: Command name for detailed information
162
+ params: Command parameters
163
+ command: Command name for detailed information
164
+
163
165
  Returns:
164
166
  Dict[str, Any]: Command help information
165
167
  """
166
- if params is None:
168
+ if not params:
167
169
  params = {}
170
+
168
171
  # If specific command is specified, return information only about it
169
- cmdname = params.get("cmdname")
170
- if cmdname:
171
- if cmdname not in self._metadata:
172
+ if "command" in params and params["command"]:
173
+ command = params["command"]
174
+ if command not in self._metadata:
172
175
  return {
173
- "error": f"Command '{cmdname}' not found",
176
+ "error": f"Command '{command}' not found",
174
177
  "available_commands": list(self._metadata.keys())
175
178
  }
179
+
176
180
  return {
177
- "cmdname": cmdname,
178
- "info": self._metadata[cmdname]
181
+ "command": command,
182
+ "info": self._metadata[command]
179
183
  }
184
+
180
185
  # Otherwise return brief information about all commands
181
186
  commands_info = {}
182
187
  for cmd, info in self._metadata.items():
@@ -185,8 +190,9 @@ class JsonRpcDispatcher(BaseDispatcher):
185
190
  "description": info["description"],
186
191
  "params_count": len(info["params"])
187
192
  }
193
+
188
194
  return {
189
195
  "commands": commands_info,
190
196
  "total": len(commands_info),
191
- "note": "Use the 'cmdname' parameter to get detailed information about a specific command"
197
+ "note": "Use the 'command' parameter to get detailed information about a specific command"
192
198
  }
@@ -12,10 +12,10 @@ Run:
12
12
  """
13
13
  import os
14
14
  import sys
15
- sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
15
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
16
16
  from typing import Any, Dict
17
17
  from mcp_proxy_adapter.adapter import MCPProxyAdapter
18
- from tests.test_mcp_proxy_adapter import MockRegistry
18
+ from mcp_proxy_adapter.testing_utils import MockRegistry
19
19
 
20
20
  # --- Setup registry and adapter ---
21
21
  registry = MockRegistry()
@@ -12,12 +12,12 @@ Run:
12
12
  """
13
13
  import os
14
14
  import sys
15
- sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__))))
15
+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
16
16
  from typing import Any, Dict
17
17
 
18
18
  # Assume MCPProxyAdapter and MockRegistry are available from src and tests
19
19
  from mcp_proxy_adapter.adapter import MCPProxyAdapter
20
- from tests.test_mcp_proxy_adapter import MockRegistry
20
+ from mcp_proxy_adapter.testing_utils import MockRegistry
21
21
 
22
22
  # --- Setup registry and adapter ---
23
23
  registry = MockRegistry()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 2.1.9
3
+ Version: 2.1.10
4
4
  Summary: Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.
5
5
  Home-page: https://github.com/vasilyvz/mcp-proxy-adapter
6
6
  Author: Vasiliy VZ
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mcp-proxy-adapter"
7
- version = "2.1.9"
7
+ version = "2.1.10"
8
8
  description = "Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -14,7 +14,7 @@ with open(os.path.join(here, 'requirements.txt'), encoding='utf-8') as f:
14
14
 
15
15
  setup(
16
16
  name="mcp-proxy-adapter",
17
- version="2.1.9",
17
+ version="2.1.10",
18
18
  description="Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.",
19
19
  long_description=long_description,
20
20
  long_description_content_type="text/markdown",
@@ -29,8 +29,6 @@ except ImportError:
29
29
  from src.adapter import MCPProxyAdapter, configure_logger
30
30
  from src.registry import CommandRegistry
31
31
 
32
- print('LOADED test_adapter.py')
33
-
34
32
  # Test command functions
35
33
  def success_command(value: int = 1) -> dict:
36
34
  """Test command that completes successfully."""
@@ -65,7 +63,7 @@ class BaseDispatcher:
65
63
  raise NotImplementedError("Method must be overridden in subclass")
66
64
 
67
65
  # Mock for command dispatcher
68
- class MockDispatcherXXX(BaseDispatcher):
66
+ class MockDispatcher(BaseDispatcher):
69
67
  """Mock for command dispatcher in tests."""
70
68
 
71
69
  def __init__(self):
@@ -73,8 +71,7 @@ class MockDispatcherXXX(BaseDispatcher):
73
71
  "success": success_command,
74
72
  "error": error_command,
75
73
  "param": param_command,
76
- "execute": self.execute_from_params,
77
- "__help": self.help_command
74
+ "execute": self.execute_from_params
78
75
  }
79
76
  self.commands_info = {
80
77
  "success": {
@@ -117,16 +114,6 @@ class MockDispatcherXXX(BaseDispatcher):
117
114
  "required": False
118
115
  }
119
116
  }
120
- },
121
- "__help": {
122
- "description": "Show help for commands",
123
- "params": {
124
- "cmdname": {
125
- "type": "string",
126
- "description": "Command name for detailed info",
127
- "required": False
128
- }
129
- }
130
117
  }
131
118
  }
132
119
 
@@ -134,8 +121,6 @@ class MockDispatcherXXX(BaseDispatcher):
134
121
  """Executes command based on parameters."""
135
122
  if "query" in params and params["query"] in self.commands:
136
123
  command = params.pop("query")
137
- if command == "help":
138
- command = "__help"
139
124
  return self.execute(command, **params)
140
125
  return {
141
126
  "available_commands": self.get_valid_commands(),
@@ -143,48 +128,25 @@ class MockDispatcherXXX(BaseDispatcher):
143
128
  }
144
129
 
145
130
  def execute(self, command, **params):
146
- print(f"[DEBUG] execute called: command={command}, params={params}")
147
- if command == "help":
148
- command = "__help"
149
131
  if command not in self.commands:
150
132
  raise KeyError(f"Unknown command: {command}")
151
- if command == "__help":
152
- return self.commands[command](params=params)
153
133
  return self.commands[command](**params)
154
134
 
155
135
  def get_valid_commands(self):
156
136
  return list(self.commands.keys())
157
137
 
158
138
  def get_command_info(self, command):
159
- if command == "help":
160
- command = "__help"
161
139
  return self.commands_info.get(command)
162
140
 
163
141
  def get_commands_info(self):
164
142
  return self.commands_info
165
143
 
166
- def help_command(self, params=None):
167
- import traceback; print(f"[DEBUG] help_command called with params: {params}"); print(f"[DEBUG] commands_info: {self.commands_info}"); traceback.print_stack()
168
- if params is None:
169
- params = {}
170
- cmdname = params.get("cmdname")
171
- if cmdname:
172
- if cmdname in self.commands_info:
173
- return {"cmdname": cmdname, "info": self.commands_info[cmdname]}
174
- else:
175
- return {"error": f"Command '{cmdname}' not found", "available_commands": list(self.commands_info.keys())}
176
- return {
177
- "commands": {cmd: {"description": info["description"], "params": info["params"]} for cmd, info in self.commands_info.items()},
178
- "total": len(self.commands_info),
179
- "note": "Use the 'cmdname' parameter to get detailed information about a specific command"
180
- }
181
-
182
144
  # Mock for CommandRegistry
183
145
  class MockRegistry:
184
146
  """Mock for CommandRegistry in tests."""
185
147
 
186
148
  def __init__(self):
187
- self.dispatcher = MockDispatcherXXX()
149
+ self.dispatcher = MockDispatcher()
188
150
  self.generators = []
189
151
 
190
152
  def get_commands_info(self):
@@ -457,9 +419,9 @@ def test_save_config_to_file(adapter, tmp_path):
457
419
 
458
420
  assert "version" in config
459
421
  assert "tools" in config
460
- assert len(config["tools"]) == 5 # Теперь 5 команд (включая help)
422
+ assert len(config["tools"]) == 4 # Corrected: now we have 4 commands
461
423
  assert "routes" in config
462
- assert len(config["routes"]) == 5 # Теперь 5 маршрутов
424
+ assert len(config["routes"]) == 4 # Corrected: now we have 4 routes, corresponding to commands
463
425
 
464
426
  def test_parameter_type_validation(test_app):
465
427
  """Test parameter type validation."""
@@ -564,62 +526,4 @@ def test_params_only_format(test_app):
564
526
  data = response.json()
565
527
  assert "result" in data
566
528
  assert "available_commands" in data["result"]
567
- assert "received_params" in data["result"]
568
-
569
- def test_jsonrpc_proxy_and_help_conflict(test_app):
570
- """Test JSON-RPC proxying and help/command param conflict."""
571
- # Обычный JSON-RPC вызов существующей команды
572
- response = test_app.post("/cmd", json={
573
- "jsonrpc": "2.0",
574
- "method": "success",
575
- "params": {"value": 3},
576
- "id": 42
577
- })
578
- assert response.status_code == 200
579
- data = response.json()
580
- assert "result" in data
581
- assert data["result"] == {"result": 6}
582
-
583
- # Вызов help по конкретной команде (не должно быть multiple values for argument 'command')
584
- response = test_app.post("/cmd", json={
585
- "jsonrpc": "2.0",
586
- "method": "help",
587
- "params": {"cmdname": "success"},
588
- "id": 43
589
- })
590
- assert response.status_code == 200
591
- data = response.json()
592
- assert "result" in data
593
- assert data["result"]["cmdname"] == "success"
594
- assert "info" in data["result"]
595
- assert "description" in data["result"]["info"]
596
-
597
- # Вызов help по несуществующей команде
598
- response = test_app.post("/cmd", json={
599
- "jsonrpc": "2.0",
600
- "method": "help",
601
- "params": {"cmdname": "not_a_command"},
602
- "id": 44
603
- })
604
- assert response.status_code == 200
605
- data = response.json()
606
- assert "result" in data
607
- # Ошибка может быть либо в data['result']['error'], либо в data['error']['message']
608
- found = False
609
- if "error" in data["result"] and "not found" in data["result"]["error"]:
610
- found = True
611
- if "error" in data and "message" in data["error"] and "not found" in data["error"]["message"]:
612
- found = True
613
- assert found, f"No 'not found' in error: {data}"
614
-
615
- # Вызов несуществующей команды
616
- response = test_app.post("/cmd", json={
617
- "jsonrpc": "2.0",
618
- "method": "not_a_command",
619
- "params": {},
620
- "id": 45
621
- })
622
- assert response.status_code == 200
623
- data = response.json()
624
- assert "error" in data
625
- assert "Unknown command" in data["error"]["message"]
529
+ assert "received_params" in data["result"]
@@ -3,7 +3,7 @@ import sys
3
3
  import os
4
4
  import pytest
5
5
 
6
- EXAMPLES_DIR = os.path.join(os.path.dirname(__file__), "..", "examples")
6
+ EXAMPLES_DIR = os.path.join(os.path.dirname(__file__), "..", "mcp_proxy_adapter", "examples")
7
7
 
8
8
  @pytest.mark.parametrize("script,expected", [
9
9
  ("help_usage.py", ["Project help", "Adapter help"]),