mcp-proxy-adapter 2.1.2__py3-none-any.whl → 2.1.3__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-2.1.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-2.1.3.dist-info/RECORD +18 -0
- mcp_proxy_adapter-2.1.3.dist-info/top_level.txt +1 -0
- docs/README.md +0 -172
- docs/README_ru.md +0 -172
- docs/architecture.md +0 -251
- docs/architecture_ru.md +0 -343
- docs/command_development.md +0 -250
- docs/command_development_ru.md +0 -593
- docs/deployment.md +0 -251
- docs/deployment_ru.md +0 -1298
- docs/examples.md +0 -254
- docs/examples_ru.md +0 -401
- docs/mcp_proxy_adapter.md +0 -251
- docs/mcp_proxy_adapter_ru.md +0 -405
- docs/quickstart.md +0 -251
- docs/quickstart_ru.md +0 -397
- docs/testing.md +0 -255
- docs/testing_ru.md +0 -469
- docs/validation_ru.md +0 -287
- examples/analyze_config.py +0 -141
- examples/basic_integration.py +0 -161
- examples/docstring_and_schema_example.py +0 -60
- examples/extension_example.py +0 -60
- examples/help_best_practices.py +0 -67
- examples/help_usage.py +0 -64
- examples/mcp_proxy_client.py +0 -131
- examples/mcp_proxy_config.json +0 -175
- examples/openapi_server.py +0 -369
- examples/project_structure_example.py +0 -47
- examples/testing_example.py +0 -53
- mcp_proxy_adapter-2.1.2.dist-info/RECORD +0 -61
- mcp_proxy_adapter-2.1.2.dist-info/top_level.txt +0 -5
- scripts/code_analyzer/code_analyzer.py +0 -328
- scripts/code_analyzer/register_commands.py +0 -446
- scripts/publish.py +0 -85
- tests/conftest.py +0 -12
- tests/test_adapter.py +0 -529
- tests/test_adapter_coverage.py +0 -274
- tests/test_basic_dispatcher.py +0 -169
- tests/test_command_registry.py +0 -328
- tests/test_examples.py +0 -32
- tests/test_mcp_proxy_adapter.py +0 -568
- tests/test_mcp_proxy_adapter_basic.py +0 -262
- tests/test_part1.py +0 -348
- tests/test_part2.py +0 -524
- tests/test_schema.py +0 -358
- tests/test_simple_adapter.py +0 -251
- {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-2.1.2.dist-info → mcp_proxy_adapter-2.1.3.dist-info}/licenses/LICENSE +0 -0
tests/test_command_registry.py
DELETED
@@ -1,328 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Tests for CommandRegistry.
|
3
|
-
"""
|
4
|
-
import sys
|
5
|
-
import os
|
6
|
-
import pytest
|
7
|
-
import tempfile
|
8
|
-
from typing import Dict, Any, Optional, List
|
9
|
-
import inspect
|
10
|
-
|
11
|
-
# Add parent directory to import path
|
12
|
-
current_dir = os.path.dirname(os.path.abspath(__file__))
|
13
|
-
parent_dir = os.path.dirname(current_dir)
|
14
|
-
if parent_dir not in sys.path:
|
15
|
-
sys.path.insert(0, parent_dir)
|
16
|
-
|
17
|
-
# Import classes for testing
|
18
|
-
try:
|
19
|
-
from mcp_proxy_adapter.registry import CommandRegistry
|
20
|
-
from mcp_proxy_adapter.dispatchers.json_rpc_dispatcher import JsonRpcDispatcher
|
21
|
-
from mcp_proxy_adapter.analyzers.docstring_analyzer import DocstringAnalyzer
|
22
|
-
from mcp_proxy_adapter.analyzers.type_analyzer import TypeAnalyzer
|
23
|
-
from mcp_proxy_adapter.validators.docstring_validator import DocstringValidator
|
24
|
-
except ImportError:
|
25
|
-
from src.registry import CommandRegistry
|
26
|
-
from src.dispatchers.json_rpc_dispatcher import JsonRpcDispatcher
|
27
|
-
from mcp_proxy_adapter.analyzers.docstring_analyzer import DocstringAnalyzer
|
28
|
-
from mcp_proxy_adapter.analyzers.type_analyzer import TypeAnalyzer
|
29
|
-
from mcp_proxy_adapter.validators.docstring_validator import DocstringValidator
|
30
|
-
|
31
|
-
|
32
|
-
# Test functions for command registration testing
|
33
|
-
|
34
|
-
def valid_command(a: int, b: int = 1) -> int:
|
35
|
-
"""
|
36
|
-
Valid function for testing.
|
37
|
-
|
38
|
-
Args:
|
39
|
-
a: First parameter
|
40
|
-
b: Second parameter
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
int: Calculation result
|
44
|
-
"""
|
45
|
-
return a + b
|
46
|
-
|
47
|
-
def invalid_docstring_command(a: int, b: int = 1) -> int:
|
48
|
-
"""
|
49
|
-
Function with invalid docstring.
|
50
|
-
|
51
|
-
Args:
|
52
|
-
a: First parameter
|
53
|
-
# Missing description for parameter b
|
54
|
-
|
55
|
-
Returns:
|
56
|
-
int: Calculation result
|
57
|
-
"""
|
58
|
-
return a + b
|
59
|
-
|
60
|
-
def invalid_annotation_command(a, b = 1):
|
61
|
-
"""
|
62
|
-
Function without type annotations.
|
63
|
-
|
64
|
-
Args:
|
65
|
-
a: First parameter
|
66
|
-
b: Second parameter
|
67
|
-
|
68
|
-
Returns:
|
69
|
-
Calculation result
|
70
|
-
"""
|
71
|
-
return a + b
|
72
|
-
|
73
|
-
def params_command(params: Dict[str, Any]) -> Dict[str, Any]:
|
74
|
-
"""
|
75
|
-
Function that accepts a dictionary of parameters.
|
76
|
-
|
77
|
-
Args:
|
78
|
-
params: Dictionary of parameters
|
79
|
-
|
80
|
-
Returns:
|
81
|
-
Dict[str, Any]: Processing result
|
82
|
-
"""
|
83
|
-
# Return the params dictionary directly
|
84
|
-
return params
|
85
|
-
|
86
|
-
|
87
|
-
@pytest.fixture
|
88
|
-
def registry():
|
89
|
-
"""Creates CommandRegistry for tests"""
|
90
|
-
return CommandRegistry(
|
91
|
-
dispatcher=JsonRpcDispatcher(),
|
92
|
-
strict=True,
|
93
|
-
auto_fix=False
|
94
|
-
)
|
95
|
-
|
96
|
-
|
97
|
-
class TestCommandRegistry:
|
98
|
-
"""Tests for CommandRegistry"""
|
99
|
-
|
100
|
-
def test_initialization(self, registry):
|
101
|
-
"""Test command registry initialization"""
|
102
|
-
# Check that standard analyzers and validators are added
|
103
|
-
assert any(isinstance(a, TypeAnalyzer) for a in registry._analyzers)
|
104
|
-
assert any(isinstance(a, DocstringAnalyzer) for a in registry._analyzers)
|
105
|
-
assert any(isinstance(v, DocstringValidator) for v in registry._validators)
|
106
|
-
|
107
|
-
# Check that dispatcher is initialized
|
108
|
-
assert registry.dispatcher is not None
|
109
|
-
assert isinstance(registry.dispatcher, JsonRpcDispatcher)
|
110
|
-
|
111
|
-
def test_analyze_handler(self, registry):
|
112
|
-
"""Test command handler analysis"""
|
113
|
-
metadata = registry.analyze_handler("valid_command", valid_command)
|
114
|
-
|
115
|
-
# Check metadata structure
|
116
|
-
assert "description" in metadata
|
117
|
-
assert "summary" in metadata
|
118
|
-
assert "parameters" in metadata
|
119
|
-
|
120
|
-
# Check that parameters are discovered
|
121
|
-
assert "a" in metadata["parameters"]
|
122
|
-
assert "b" in metadata["parameters"]
|
123
|
-
|
124
|
-
# Check parameter types
|
125
|
-
assert metadata["parameters"]["a"]["type"] == "integer"
|
126
|
-
assert metadata["parameters"]["b"]["type"] == "integer"
|
127
|
-
|
128
|
-
# Check descriptions and requirement flags
|
129
|
-
assert "description" in metadata["parameters"]["a"]
|
130
|
-
assert "description" in metadata["parameters"]["b"]
|
131
|
-
assert metadata["parameters"]["a"]["required"] is True
|
132
|
-
assert metadata["parameters"]["b"]["required"] is False
|
133
|
-
|
134
|
-
def test_validate_handler_valid(self, registry):
|
135
|
-
"""Test validation of a valid handler"""
|
136
|
-
metadata = registry.analyze_handler("valid_command", valid_command)
|
137
|
-
is_valid, errors = registry.validate_handler("valid_command", valid_command, metadata)
|
138
|
-
|
139
|
-
assert is_valid is True
|
140
|
-
assert len(errors) == 0
|
141
|
-
|
142
|
-
def test_validate_handler_invalid_docstring(self, registry):
|
143
|
-
"""Test validation of a handler with invalid docstring"""
|
144
|
-
metadata = registry.analyze_handler("invalid_docstring", invalid_docstring_command)
|
145
|
-
is_valid, errors = registry.validate_handler("invalid_docstring", invalid_docstring_command, metadata)
|
146
|
-
|
147
|
-
assert is_valid is False
|
148
|
-
assert len(errors) > 0
|
149
|
-
# Check that the error is related to missing description for parameter b
|
150
|
-
assert any("parameter 'b'" in error.lower() for error in errors)
|
151
|
-
|
152
|
-
def test_validate_handler_invalid_annotation(self, registry):
|
153
|
-
"""Test validation of a handler without type annotations"""
|
154
|
-
metadata = registry.analyze_handler("invalid_annotation", invalid_annotation_command)
|
155
|
-
is_valid, errors = registry.validate_handler("invalid_annotation", invalid_annotation_command, metadata)
|
156
|
-
|
157
|
-
assert is_valid is False
|
158
|
-
assert len(errors) > 0
|
159
|
-
# Check that the error is related to missing type annotations
|
160
|
-
assert any("type annotation" in error.lower() for error in errors)
|
161
|
-
|
162
|
-
def test_register_command_valid(self, registry):
|
163
|
-
"""Test registration of a valid command"""
|
164
|
-
result = registry.register_command("valid", valid_command)
|
165
|
-
assert result is True
|
166
|
-
|
167
|
-
# Check that the command is registered in the dispatcher
|
168
|
-
assert "valid" in registry.dispatcher.get_valid_commands()
|
169
|
-
|
170
|
-
# Check that the command can be executed
|
171
|
-
assert registry.dispatcher.execute("valid", a=5, b=3) == 8
|
172
|
-
|
173
|
-
def test_register_command_invalid_strict(self, registry):
|
174
|
-
"""Test registration of an invalid command in strict mode"""
|
175
|
-
# In strict mode, a command with errors should not be registered
|
176
|
-
result = registry.register_command("invalid_docstring", invalid_docstring_command)
|
177
|
-
assert result is False
|
178
|
-
|
179
|
-
# Check that the command is not registered in the dispatcher
|
180
|
-
assert "invalid_docstring" not in registry.dispatcher.get_valid_commands()
|
181
|
-
|
182
|
-
def test_register_command_invalid_not_strict(self):
|
183
|
-
"""Test registration of an invalid command in non-strict mode"""
|
184
|
-
# Create registry in non-strict mode
|
185
|
-
registry = CommandRegistry(strict=False, auto_fix=False)
|
186
|
-
|
187
|
-
# In non-strict mode, a command with errors should be registered
|
188
|
-
result = registry.register_command("invalid_docstring", invalid_docstring_command)
|
189
|
-
assert result is True
|
190
|
-
|
191
|
-
# Check that the command is registered in the dispatcher
|
192
|
-
assert "invalid_docstring" in registry.dispatcher.get_valid_commands()
|
193
|
-
|
194
|
-
def test_register_command_invalid_auto_fix(self):
|
195
|
-
"""Test registration of an invalid command with auto-fix"""
|
196
|
-
# Create registry in auto-fix mode
|
197
|
-
registry = CommandRegistry(strict=True, auto_fix=True)
|
198
|
-
|
199
|
-
# In auto-fix mode, a command with errors should be registered
|
200
|
-
result = registry.register_command("invalid_docstring", invalid_docstring_command)
|
201
|
-
assert result is True
|
202
|
-
|
203
|
-
# Check that the command is registered in the dispatcher
|
204
|
-
assert "invalid_docstring" in registry.dispatcher.get_valid_commands()
|
205
|
-
|
206
|
-
def test_params_command(self, registry):
|
207
|
-
"""Test command with params parameter"""
|
208
|
-
result = registry.register_command("params_command", params_command)
|
209
|
-
assert result is True
|
210
|
-
|
211
|
-
# Check that the command is registered
|
212
|
-
assert "params_command" in registry.dispatcher.get_valid_commands()
|
213
|
-
|
214
|
-
# Test executing the command with params parameter
|
215
|
-
test_params = {"a": 1, "b": 2}
|
216
|
-
# Params are passed in the 'params' field
|
217
|
-
assert registry.dispatcher.execute("params_command", params=test_params) == {"params": test_params}
|
218
|
-
|
219
|
-
|
220
|
-
class TestCommandRegistryWithModules:
|
221
|
-
"""Tests for CommandRegistry with command modules"""
|
222
|
-
|
223
|
-
@pytest.fixture
|
224
|
-
def temp_module_dir(self):
|
225
|
-
"""Creates a temporary directory with command modules for testing"""
|
226
|
-
with tempfile.TemporaryDirectory() as temp_dir:
|
227
|
-
# Create directory structure for modules
|
228
|
-
commands_dir = os.path.join(temp_dir, "commands")
|
229
|
-
test_dir = os.path.join(commands_dir, "test")
|
230
|
-
os.makedirs(test_dir, exist_ok=True)
|
231
|
-
|
232
|
-
# Create __init__.py files
|
233
|
-
with open(os.path.join(commands_dir, "__init__.py"), "w") as f:
|
234
|
-
f.write("")
|
235
|
-
with open(os.path.join(test_dir, "__init__.py"), "w") as f:
|
236
|
-
f.write("")
|
237
|
-
|
238
|
-
# Create file with test command
|
239
|
-
test_command_path = os.path.join(temp_dir, "commands", "test", "test_command.py")
|
240
|
-
with open(test_command_path, "w") as f:
|
241
|
-
f.write("""
|
242
|
-
from typing import Dict, Any
|
243
|
-
|
244
|
-
# Function name needs to match expected test_command in assertions
|
245
|
-
def test_command_function(a: int, b: int = 1) -> int:
|
246
|
-
\"\"\"
|
247
|
-
Test command for adding numbers.
|
248
|
-
|
249
|
-
Args:
|
250
|
-
a: First number
|
251
|
-
b: Second number
|
252
|
-
|
253
|
-
Returns:
|
254
|
-
int: Sum of numbers
|
255
|
-
\"\"\"
|
256
|
-
return a + b
|
257
|
-
|
258
|
-
# This is used to define the command name
|
259
|
-
test_command_function.command_name = "test_command"
|
260
|
-
|
261
|
-
COMMAND = {
|
262
|
-
"description": "Test command for adding numbers",
|
263
|
-
"parameters": {
|
264
|
-
"a": {
|
265
|
-
"type": "integer",
|
266
|
-
"description": "First number",
|
267
|
-
"required": True
|
268
|
-
},
|
269
|
-
"b": {
|
270
|
-
"type": "integer",
|
271
|
-
"description": "Second number",
|
272
|
-
"required": False,
|
273
|
-
"default": 1
|
274
|
-
}
|
275
|
-
}
|
276
|
-
}
|
277
|
-
""")
|
278
|
-
|
279
|
-
# Verify file exists
|
280
|
-
print(f"Created test file at: {test_command_path}")
|
281
|
-
print(f"File exists: {os.path.exists(test_command_path)}")
|
282
|
-
|
283
|
-
# Add temporary directory path to sys.path
|
284
|
-
sys.path.insert(0, temp_dir)
|
285
|
-
yield temp_dir
|
286
|
-
|
287
|
-
# Remove path from sys.path
|
288
|
-
sys.path.remove(temp_dir)
|
289
|
-
|
290
|
-
def test_scan_modules(self, temp_module_dir):
|
291
|
-
"""Test scanning modules with commands"""
|
292
|
-
registry = CommandRegistry(strict=True, auto_fix=False)
|
293
|
-
|
294
|
-
# Scan modules
|
295
|
-
registry.scan_modules(["commands.test"])
|
296
|
-
|
297
|
-
# Get command handlers
|
298
|
-
handlers = registry.find_command_handlers()
|
299
|
-
|
300
|
-
# Check that the handler is found
|
301
|
-
assert "test_command" in handlers
|
302
|
-
assert callable(handlers["test_command"])
|
303
|
-
|
304
|
-
def test_register_all_commands(self, temp_module_dir):
|
305
|
-
"""Test registering all commands from modules"""
|
306
|
-
# Create a simple function for testing
|
307
|
-
def test_command(a: int, b: int = 1) -> int:
|
308
|
-
"""
|
309
|
-
Test command for adding numbers.
|
310
|
-
|
311
|
-
Args:
|
312
|
-
a: First number
|
313
|
-
b: Second number
|
314
|
-
|
315
|
-
Returns:
|
316
|
-
int: Sum of numbers
|
317
|
-
"""
|
318
|
-
return a + b
|
319
|
-
|
320
|
-
# Create registry and register the command directly
|
321
|
-
registry = CommandRegistry(strict=True, auto_fix=False)
|
322
|
-
registry.register_command("test_command", test_command)
|
323
|
-
|
324
|
-
# Check that the command is registered
|
325
|
-
assert "test_command" in registry.dispatcher.get_valid_commands(), f"Available commands: {registry.dispatcher.get_valid_commands()}"
|
326
|
-
|
327
|
-
# Check that the command can be executed
|
328
|
-
assert registry.dispatcher.execute("test_command", a=5, b=3) == 8
|
tests/test_examples.py
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
import subprocess
|
2
|
-
import sys
|
3
|
-
import os
|
4
|
-
import pytest
|
5
|
-
|
6
|
-
EXAMPLES_DIR = os.path.join(os.path.dirname(__file__), "..", "examples")
|
7
|
-
|
8
|
-
@pytest.mark.parametrize("script,expected", [
|
9
|
-
("help_usage.py", ["Project help", "Adapter help"]),
|
10
|
-
("help_best_practices.py", ["Project help", "Adapter help"]),
|
11
|
-
("docstring_and_schema_example.py", ["Tool description from docstring", "sum of two numbers"]),
|
12
|
-
("testing_example.py", ["All tests passed"]),
|
13
|
-
("extension_example.py", ["Ping", "Help (all)", "Help (ping)", "Help (notfound)"]),
|
14
|
-
])
|
15
|
-
def test_example_scripts(script, expected):
|
16
|
-
"""Test that example script runs and produces expected output."""
|
17
|
-
script_path = os.path.join(EXAMPLES_DIR, script)
|
18
|
-
result = subprocess.run([sys.executable, script_path], capture_output=True, text=True)
|
19
|
-
assert result.returncode == 0, f"{script} failed: {result.stderr}"
|
20
|
-
for key in expected:
|
21
|
-
assert key in result.stdout, f"{script} output missing: {key}"
|
22
|
-
|
23
|
-
# FastAPI app smoke-test (project_structure_example.py)
|
24
|
-
def test_project_structure_example_import():
|
25
|
-
"""Test that project_structure_example.py can be imported and app initialized."""
|
26
|
-
import importlib.util
|
27
|
-
script_path = os.path.join(EXAMPLES_DIR, "project_structure_example.py")
|
28
|
-
spec = importlib.util.spec_from_file_location("project_structure_example", script_path)
|
29
|
-
module = importlib.util.module_from_spec(spec)
|
30
|
-
spec.loader.exec_module(module)
|
31
|
-
assert hasattr(module, "app"), "FastAPI app not found in project_structure_example.py"
|
32
|
-
assert hasattr(module, "adapter"), "Adapter not found in project_structure_example.py"
|