mcp-proxy-adapter 3.1.6__py3-none-any.whl → 4.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.
- mcp_proxy_adapter/api/app.py +65 -27
- mcp_proxy_adapter/api/handlers.py +1 -1
- mcp_proxy_adapter/api/middleware/error_handling.py +11 -10
- mcp_proxy_adapter/api/tool_integration.py +5 -2
- mcp_proxy_adapter/api/tools.py +3 -3
- mcp_proxy_adapter/commands/base.py +19 -1
- mcp_proxy_adapter/commands/command_registry.py +243 -6
- mcp_proxy_adapter/commands/hooks.py +260 -0
- mcp_proxy_adapter/commands/reload_command.py +211 -0
- mcp_proxy_adapter/commands/reload_settings_command.py +125 -0
- mcp_proxy_adapter/commands/settings_command.py +189 -0
- mcp_proxy_adapter/config.py +16 -1
- mcp_proxy_adapter/core/__init__.py +44 -0
- mcp_proxy_adapter/core/logging.py +87 -34
- mcp_proxy_adapter/core/settings.py +376 -0
- mcp_proxy_adapter/core/utils.py +2 -2
- mcp_proxy_adapter/custom_openapi.py +81 -2
- mcp_proxy_adapter/examples/README.md +124 -0
- mcp_proxy_adapter/examples/__init__.py +7 -0
- mcp_proxy_adapter/examples/basic_server/README.md +60 -0
- mcp_proxy_adapter/examples/basic_server/__init__.py +7 -0
- mcp_proxy_adapter/examples/basic_server/basic_custom_settings.json +39 -0
- mcp_proxy_adapter/examples/basic_server/config.json +35 -0
- mcp_proxy_adapter/examples/basic_server/custom_settings_example.py +238 -0
- mcp_proxy_adapter/examples/basic_server/server.py +98 -0
- mcp_proxy_adapter/examples/custom_commands/README.md +127 -0
- mcp_proxy_adapter/examples/custom_commands/__init__.py +27 -0
- mcp_proxy_adapter/examples/custom_commands/advanced_hooks.py +250 -0
- mcp_proxy_adapter/examples/custom_commands/auto_commands/__init__.py +6 -0
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_echo_command.py +103 -0
- mcp_proxy_adapter/examples/custom_commands/auto_commands/auto_info_command.py +111 -0
- mcp_proxy_adapter/examples/custom_commands/config.json +62 -0
- mcp_proxy_adapter/examples/custom_commands/custom_health_command.py +169 -0
- mcp_proxy_adapter/examples/custom_commands/custom_help_command.py +215 -0
- mcp_proxy_adapter/examples/custom_commands/custom_openapi_generator.py +76 -0
- mcp_proxy_adapter/examples/custom_commands/custom_settings.json +96 -0
- mcp_proxy_adapter/examples/custom_commands/custom_settings_manager.py +241 -0
- mcp_proxy_adapter/examples/custom_commands/data_transform_command.py +135 -0
- mcp_proxy_adapter/examples/custom_commands/echo_command.py +122 -0
- mcp_proxy_adapter/examples/custom_commands/hooks.py +230 -0
- mcp_proxy_adapter/examples/custom_commands/intercept_command.py +123 -0
- mcp_proxy_adapter/examples/custom_commands/manual_echo_command.py +103 -0
- mcp_proxy_adapter/examples/custom_commands/server.py +223 -0
- mcp_proxy_adapter/examples/custom_commands/test_hooks.py +176 -0
- mcp_proxy_adapter/examples/deployment/README.md +49 -0
- mcp_proxy_adapter/examples/deployment/__init__.py +7 -0
- mcp_proxy_adapter/examples/deployment/config.development.json +8 -0
- {examples/basic_example → mcp_proxy_adapter/examples/deployment}/config.json +11 -7
- mcp_proxy_adapter/examples/deployment/config.production.json +12 -0
- mcp_proxy_adapter/examples/deployment/config.staging.json +11 -0
- mcp_proxy_adapter/examples/deployment/docker-compose.yml +31 -0
- mcp_proxy_adapter/examples/deployment/run.sh +43 -0
- mcp_proxy_adapter/examples/deployment/run_docker.sh +84 -0
- mcp_proxy_adapter/openapi.py +3 -2
- mcp_proxy_adapter/tests/api/test_custom_openapi.py +617 -0
- mcp_proxy_adapter/tests/api/test_handlers.py +522 -0
- mcp_proxy_adapter/tests/api/test_schemas.py +546 -0
- mcp_proxy_adapter/tests/api/test_tool_integration.py +531 -0
- mcp_proxy_adapter/tests/unit/test_base_command.py +391 -85
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-3.1.6.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/METADATA +1 -1
- mcp_proxy_adapter-4.0.0.dist-info/RECORD +110 -0
- {mcp_proxy_adapter-3.1.6.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/WHEEL +1 -1
- {mcp_proxy_adapter-3.1.6.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/top_level.txt +0 -1
- examples/__init__.py +0 -19
- examples/anti_patterns/README.md +0 -51
- examples/anti_patterns/__init__.py +0 -9
- examples/anti_patterns/bad_design/README.md +0 -72
- examples/anti_patterns/bad_design/global_state.py +0 -170
- examples/anti_patterns/bad_design/monolithic_command.py +0 -272
- examples/basic_example/README.md +0 -245
- examples/basic_example/__init__.py +0 -8
- examples/basic_example/commands/__init__.py +0 -5
- examples/basic_example/commands/echo_command.py +0 -95
- examples/basic_example/commands/math_command.py +0 -151
- examples/basic_example/commands/time_command.py +0 -152
- examples/basic_example/docs/EN/README.md +0 -177
- examples/basic_example/docs/RU/README.md +0 -177
- examples/basic_example/server.py +0 -151
- examples/basic_example/tests/conftest.py +0 -243
- examples/check_vstl_schema.py +0 -106
- examples/commands/echo_command.py +0 -52
- examples/commands/echo_command_di.py +0 -152
- examples/commands/echo_result.py +0 -65
- examples/commands/get_date_command.py +0 -98
- examples/commands/new_uuid4_command.py +0 -91
- examples/complete_example/Dockerfile +0 -24
- examples/complete_example/README.md +0 -92
- examples/complete_example/__init__.py +0 -8
- examples/complete_example/commands/__init__.py +0 -5
- examples/complete_example/commands/system_command.py +0 -328
- examples/complete_example/config.json +0 -41
- examples/complete_example/configs/config.dev.yaml +0 -40
- examples/complete_example/configs/config.docker.yaml +0 -40
- examples/complete_example/docker-compose.yml +0 -35
- examples/complete_example/requirements.txt +0 -20
- examples/complete_example/server.py +0 -113
- examples/di_example/.pytest_cache/README.md +0 -8
- examples/di_example/server.py +0 -249
- examples/fix_vstl_help.py +0 -123
- examples/minimal_example/README.md +0 -65
- examples/minimal_example/__init__.py +0 -8
- examples/minimal_example/config.json +0 -14
- examples/minimal_example/main.py +0 -136
- examples/minimal_example/simple_server.py +0 -163
- examples/minimal_example/tests/conftest.py +0 -171
- examples/minimal_example/tests/test_hello_command.py +0 -111
- examples/minimal_example/tests/test_integration.py +0 -181
- examples/patch_vstl_service.py +0 -105
- examples/patch_vstl_service_mcp.py +0 -108
- examples/server.py +0 -69
- examples/simple_server.py +0 -128
- examples/test_package_3.1.4.py +0 -177
- examples/test_server.py +0 -134
- examples/tool_description_example.py +0 -82
- mcp_proxy_adapter/py.typed +0 -0
- mcp_proxy_adapter-3.1.6.dist-info/RECORD +0 -118
- {mcp_proxy_adapter-3.1.6.dist-info → mcp_proxy_adapter-4.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,243 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Pytest configuration and fixtures for basic example tests.
|
3
|
-
|
4
|
-
This module provides fixtures for testing the basic microservice example,
|
5
|
-
including running an actual server instance for integration tests.
|
6
|
-
All commands in the microservice are implemented as asynchronous functions.
|
7
|
-
"""
|
8
|
-
|
9
|
-
import os
|
10
|
-
import sys
|
11
|
-
import time
|
12
|
-
import socket
|
13
|
-
import asyncio
|
14
|
-
import threading
|
15
|
-
import multiprocessing
|
16
|
-
from typing import Callable, Dict, Any, List
|
17
|
-
|
18
|
-
import pytest
|
19
|
-
import requests
|
20
|
-
|
21
|
-
# Add parent directory to path for imports
|
22
|
-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
23
|
-
|
24
|
-
# Import the server module from the parent directory
|
25
|
-
import server as server_module
|
26
|
-
from commands.echo_command import EchoCommand
|
27
|
-
from commands.math_command import MathCommand
|
28
|
-
from commands.time_command import TimeCommand
|
29
|
-
|
30
|
-
|
31
|
-
def find_free_port() -> int:
|
32
|
-
"""
|
33
|
-
Find a free port on localhost.
|
34
|
-
|
35
|
-
Returns:
|
36
|
-
Free port number
|
37
|
-
"""
|
38
|
-
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
39
|
-
sock.bind(('localhost', 0))
|
40
|
-
return sock.getsockname()[1]
|
41
|
-
|
42
|
-
|
43
|
-
class ServerProcess:
|
44
|
-
"""Helper class to manage server process."""
|
45
|
-
|
46
|
-
def __init__(self, port: int):
|
47
|
-
"""
|
48
|
-
Initialize server process with a specified port.
|
49
|
-
|
50
|
-
Args:
|
51
|
-
port: Port number to use
|
52
|
-
"""
|
53
|
-
self.port = port
|
54
|
-
self.process = None
|
55
|
-
|
56
|
-
def start(self) -> None:
|
57
|
-
"""Start the server in a separate process."""
|
58
|
-
def run_server():
|
59
|
-
# Mock the configuration to use the test port
|
60
|
-
os.environ["TEST_SERVER_PORT"] = str(self.port)
|
61
|
-
server_module.main()
|
62
|
-
|
63
|
-
self.process = multiprocessing.Process(target=run_server)
|
64
|
-
self.process.daemon = True
|
65
|
-
self.process.start()
|
66
|
-
|
67
|
-
# Wait for server to start
|
68
|
-
self._wait_for_server()
|
69
|
-
|
70
|
-
def stop(self) -> None:
|
71
|
-
"""Stop the server process."""
|
72
|
-
if self.process and self.process.is_alive():
|
73
|
-
self.process.terminate()
|
74
|
-
self.process.join(timeout=2)
|
75
|
-
|
76
|
-
def _wait_for_server(self, max_attempts: int = 10) -> None:
|
77
|
-
"""
|
78
|
-
Wait for the server to become available.
|
79
|
-
|
80
|
-
Args:
|
81
|
-
max_attempts: Maximum number of connection attempts
|
82
|
-
"""
|
83
|
-
for i in range(max_attempts):
|
84
|
-
try:
|
85
|
-
response = requests.get(f"http://localhost:{self.port}/health")
|
86
|
-
if response.status_code == 200:
|
87
|
-
return
|
88
|
-
except requests.ConnectionError:
|
89
|
-
pass
|
90
|
-
|
91
|
-
time.sleep(0.5)
|
92
|
-
|
93
|
-
raise TimeoutError(f"Server did not start within {max_attempts * 0.5} seconds")
|
94
|
-
|
95
|
-
|
96
|
-
@pytest.fixture
|
97
|
-
def server_port() -> int:
|
98
|
-
"""
|
99
|
-
Fixture that provides a free port for the test server.
|
100
|
-
|
101
|
-
Returns:
|
102
|
-
Port number
|
103
|
-
"""
|
104
|
-
return find_free_port()
|
105
|
-
|
106
|
-
|
107
|
-
@pytest.fixture
|
108
|
-
def server(server_port: int) -> ServerProcess:
|
109
|
-
"""
|
110
|
-
Fixture that provides a running server instance.
|
111
|
-
|
112
|
-
Args:
|
113
|
-
server_port: Port to run the server on
|
114
|
-
|
115
|
-
Returns:
|
116
|
-
Server process object
|
117
|
-
"""
|
118
|
-
server_process = ServerProcess(server_port)
|
119
|
-
server_process.start()
|
120
|
-
|
121
|
-
yield server_process
|
122
|
-
|
123
|
-
server_process.stop()
|
124
|
-
|
125
|
-
|
126
|
-
@pytest.fixture
|
127
|
-
def api_url(server_port: int) -> str:
|
128
|
-
"""
|
129
|
-
Fixture that provides the base API URL.
|
130
|
-
|
131
|
-
Args:
|
132
|
-
server_port: Server port
|
133
|
-
|
134
|
-
Returns:
|
135
|
-
Base API URL
|
136
|
-
"""
|
137
|
-
return f"http://localhost:{server_port}"
|
138
|
-
|
139
|
-
|
140
|
-
@pytest.fixture
|
141
|
-
def jsonrpc_client(api_url: str) -> Callable:
|
142
|
-
"""
|
143
|
-
Fixture that provides a JSON-RPC client function.
|
144
|
-
|
145
|
-
Args:
|
146
|
-
api_url: Base API URL
|
147
|
-
|
148
|
-
Returns:
|
149
|
-
Function to make JSON-RPC requests
|
150
|
-
"""
|
151
|
-
def make_request(method: str, params: Dict[str, Any], request_id: int = 1) -> Dict[str, Any]:
|
152
|
-
"""
|
153
|
-
Make a JSON-RPC request.
|
154
|
-
|
155
|
-
Args:
|
156
|
-
method: Method name
|
157
|
-
params: Method parameters
|
158
|
-
request_id: Request ID
|
159
|
-
|
160
|
-
Returns:
|
161
|
-
JSON-RPC response
|
162
|
-
"""
|
163
|
-
payload = {
|
164
|
-
"jsonrpc": "2.0",
|
165
|
-
"method": method,
|
166
|
-
"params": params,
|
167
|
-
"id": request_id
|
168
|
-
}
|
169
|
-
|
170
|
-
response = requests.post(
|
171
|
-
f"{api_url}/api/jsonrpc",
|
172
|
-
json=payload,
|
173
|
-
headers={"Content-Type": "application/json"}
|
174
|
-
)
|
175
|
-
|
176
|
-
return response.json()
|
177
|
-
|
178
|
-
return make_request
|
179
|
-
|
180
|
-
|
181
|
-
@pytest.fixture
|
182
|
-
def batch_jsonrpc_client(api_url: str) -> Callable:
|
183
|
-
"""
|
184
|
-
Fixture that provides a batch JSON-RPC client function.
|
185
|
-
|
186
|
-
Args:
|
187
|
-
api_url: Base API URL
|
188
|
-
|
189
|
-
Returns:
|
190
|
-
Function to make batch JSON-RPC requests
|
191
|
-
"""
|
192
|
-
def make_batch_request(requests_data: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
193
|
-
"""
|
194
|
-
Make a batch JSON-RPC request.
|
195
|
-
|
196
|
-
Args:
|
197
|
-
requests_data: List of request objects
|
198
|
-
|
199
|
-
Returns:
|
200
|
-
List of JSON-RPC responses
|
201
|
-
"""
|
202
|
-
response = requests.post(
|
203
|
-
f"{api_url}/api/jsonrpc",
|
204
|
-
json=requests_data,
|
205
|
-
headers={"Content-Type": "application/json"}
|
206
|
-
)
|
207
|
-
|
208
|
-
return response.json()
|
209
|
-
|
210
|
-
return make_batch_request
|
211
|
-
|
212
|
-
|
213
|
-
@pytest.fixture
|
214
|
-
def echo_command() -> EchoCommand:
|
215
|
-
"""
|
216
|
-
Fixture that provides an instance of EchoCommand.
|
217
|
-
|
218
|
-
Returns:
|
219
|
-
EchoCommand instance
|
220
|
-
"""
|
221
|
-
return EchoCommand()
|
222
|
-
|
223
|
-
|
224
|
-
@pytest.fixture
|
225
|
-
def math_command() -> MathCommand:
|
226
|
-
"""
|
227
|
-
Fixture that provides an instance of MathCommand.
|
228
|
-
|
229
|
-
Returns:
|
230
|
-
MathCommand instance
|
231
|
-
"""
|
232
|
-
return MathCommand()
|
233
|
-
|
234
|
-
|
235
|
-
@pytest.fixture
|
236
|
-
def time_command() -> TimeCommand:
|
237
|
-
"""
|
238
|
-
Fixture that provides an instance of TimeCommand.
|
239
|
-
|
240
|
-
Returns:
|
241
|
-
TimeCommand instance
|
242
|
-
"""
|
243
|
-
return TimeCommand()
|
examples/check_vstl_schema.py
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
Скрипт для проверки схемы команды help в сервисе VSTL
|
4
|
-
"""
|
5
|
-
|
6
|
-
import json
|
7
|
-
import requests
|
8
|
-
from typing import Dict, Any, Optional
|
9
|
-
|
10
|
-
# URL и заголовки для VSTL сервиса
|
11
|
-
VSTL_URL = "http://localhost:8007/cmd"
|
12
|
-
HEADERS = {"Content-Type": "application/json"}
|
13
|
-
|
14
|
-
def send_json_rpc(method: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
15
|
-
"""
|
16
|
-
Отправляет JSON-RPC запрос и возвращает ответ
|
17
|
-
|
18
|
-
Args:
|
19
|
-
method: Имя метода
|
20
|
-
params: Параметры запроса
|
21
|
-
|
22
|
-
Returns:
|
23
|
-
Dict[str, Any]: Ответ сервера
|
24
|
-
"""
|
25
|
-
# Формируем JSON-RPC запрос
|
26
|
-
payload = {
|
27
|
-
"jsonrpc": "2.0",
|
28
|
-
"method": method,
|
29
|
-
"id": 1
|
30
|
-
}
|
31
|
-
|
32
|
-
# Добавляем параметры, если они есть
|
33
|
-
if params is not None:
|
34
|
-
payload["params"] = params
|
35
|
-
|
36
|
-
print(f"Отправляем запрос: {json.dumps(payload, indent=2)}")
|
37
|
-
|
38
|
-
# Отправляем запрос
|
39
|
-
response = requests.post(VSTL_URL, json=payload, headers=HEADERS)
|
40
|
-
|
41
|
-
# Возвращаем ответ
|
42
|
-
return response.json()
|
43
|
-
|
44
|
-
def test_help_command():
|
45
|
-
"""
|
46
|
-
Проверяет команду help в различных вариантах
|
47
|
-
"""
|
48
|
-
print("\n=== Проверка команды help без параметров ===")
|
49
|
-
response = send_json_rpc("help")
|
50
|
-
print(f"Ответ: {json.dumps(response, indent=2)}")
|
51
|
-
|
52
|
-
print("\n=== Проверка команды help с пустыми параметрами ===")
|
53
|
-
response = send_json_rpc("help", {})
|
54
|
-
print(f"Ответ: {json.dumps(response, indent=2)}")
|
55
|
-
|
56
|
-
print("\n=== Проверка команды help с параметром cmdname=null ===")
|
57
|
-
response = send_json_rpc("help", {"cmdname": None})
|
58
|
-
print(f"Ответ: {json.dumps(response, indent=2)}")
|
59
|
-
|
60
|
-
print("\n=== Проверка команды help с параметром cmdname=\"config\" ===")
|
61
|
-
response = send_json_rpc("help", {"cmdname": "config"})
|
62
|
-
print(f"Ответ: {json.dumps(response, indent=2)}")
|
63
|
-
|
64
|
-
# Проверяем workaround с передачей строки "null"
|
65
|
-
print("\n=== Проверка команды help с параметром cmdname=\"null\" ===")
|
66
|
-
response = send_json_rpc("help", {"cmdname": "null"})
|
67
|
-
print(f"Ответ: {json.dumps(response, indent=2)}")
|
68
|
-
|
69
|
-
def check_schema():
|
70
|
-
"""
|
71
|
-
Проверяет схему команд и ищет обязательные параметры
|
72
|
-
"""
|
73
|
-
print("\n=== Проверка схемы команд ===")
|
74
|
-
|
75
|
-
# Запрашиваем список всех доступных команд
|
76
|
-
health_response = send_json_rpc("health")
|
77
|
-
print(f"Здоровье сервиса: {json.dumps(health_response, indent=2)}")
|
78
|
-
|
79
|
-
# Проверяем команду config для получения схемы
|
80
|
-
config_response = send_json_rpc("config", {"operation": "get"})
|
81
|
-
print(f"Конфигурация: {json.dumps(config_response, indent=2)}")
|
82
|
-
|
83
|
-
# Пробуем с явным указанием строки вместо null
|
84
|
-
print("\n=== Проверка команды help с cmdname=\"\" (пустая строка) ===")
|
85
|
-
response = send_json_rpc("help", {"cmdname": ""})
|
86
|
-
print(f"Ответ: {json.dumps(response, indent=2)}")
|
87
|
-
|
88
|
-
# Создаем свой вариант с переопределением параметров
|
89
|
-
print("\n=== Проверка специального запроса с kwargs=null ===")
|
90
|
-
# Прямая отправка JSON с null значением для kwargs
|
91
|
-
special_payload = {
|
92
|
-
"jsonrpc": "2.0",
|
93
|
-
"method": "help",
|
94
|
-
"params": {"kwargs": None},
|
95
|
-
"id": 1
|
96
|
-
}
|
97
|
-
response = requests.post(VSTL_URL, json=special_payload, headers=HEADERS)
|
98
|
-
print(f"Ответ: {json.dumps(response.json(), indent=2)}")
|
99
|
-
|
100
|
-
if __name__ == "__main__":
|
101
|
-
print("=== Диагностика проблемы с командой help в сервисе VSTL ===")
|
102
|
-
try:
|
103
|
-
test_help_command()
|
104
|
-
check_schema()
|
105
|
-
except Exception as e:
|
106
|
-
print(f"Ошибка при выполнении: {e}")
|
@@ -1,52 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Module with echo command implementation.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from typing import Any, Dict, Optional, ClassVar, Type
|
6
|
-
|
7
|
-
from pydantic import BaseModel, Field, ValidationError as PydanticValidationError
|
8
|
-
|
9
|
-
from mcp_proxy_adapter.commands.base import Command
|
10
|
-
from examples.commands.echo_result import EchoResult
|
11
|
-
from mcp_proxy_adapter.core.errors import ValidationError
|
12
|
-
from mcp_proxy_adapter.core.logging import logger
|
13
|
-
|
14
|
-
|
15
|
-
class EchoCommand(Command):
|
16
|
-
"""
|
17
|
-
Command that echoes back the parameters it receives.
|
18
|
-
|
19
|
-
This command is useful for testing parameter passing and debugging.
|
20
|
-
"""
|
21
|
-
|
22
|
-
name: ClassVar[str] = "echo"
|
23
|
-
result_class: ClassVar[Type[EchoResult]] = EchoResult
|
24
|
-
|
25
|
-
@classmethod
|
26
|
-
def get_schema(cls) -> Dict[str, Any]:
|
27
|
-
"""
|
28
|
-
Returns JSON schema for command parameters validation.
|
29
|
-
|
30
|
-
Returns:
|
31
|
-
Dictionary with JSON schema.
|
32
|
-
"""
|
33
|
-
return {
|
34
|
-
"type": "object",
|
35
|
-
"additionalProperties": True,
|
36
|
-
"description": "Any parameters will be echoed back in the response"
|
37
|
-
}
|
38
|
-
|
39
|
-
async def execute(self, **kwargs) -> EchoResult:
|
40
|
-
"""
|
41
|
-
Executes echo command and returns the parameters back.
|
42
|
-
|
43
|
-
Args:
|
44
|
-
**kwargs: Any parameters to echo back.
|
45
|
-
|
46
|
-
Returns:
|
47
|
-
EchoResult: Command execution result with the parameters.
|
48
|
-
"""
|
49
|
-
logger.debug(f"Echo command received parameters: {kwargs}")
|
50
|
-
|
51
|
-
# Simply return the parameters that were passed
|
52
|
-
return EchoResult(params=kwargs)
|
@@ -1,152 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Example command with dependency injection.
|
3
|
-
|
4
|
-
This module demonstrates how to use dependency injection in commands.
|
5
|
-
"""
|
6
|
-
|
7
|
-
from typing import Any, Dict, List, Optional
|
8
|
-
|
9
|
-
from mcp_proxy_adapter.commands import Command, SuccessResult
|
10
|
-
from mcp_proxy_adapter.commands.result import CommandResult
|
11
|
-
|
12
|
-
|
13
|
-
class EchoCommandResult(SuccessResult):
|
14
|
-
"""
|
15
|
-
Result of echo command execution.
|
16
|
-
"""
|
17
|
-
|
18
|
-
def __init__(self, message: str, timestamp: str, **kwargs):
|
19
|
-
"""
|
20
|
-
Initializes echo command result.
|
21
|
-
|
22
|
-
Args:
|
23
|
-
message: Echoed message
|
24
|
-
timestamp: Time of execution
|
25
|
-
**kwargs: Additional parameters
|
26
|
-
"""
|
27
|
-
data = {"message": message, "timestamp": timestamp}
|
28
|
-
data.update(kwargs)
|
29
|
-
super().__init__(data=data, message=f"Echo response: {message}")
|
30
|
-
|
31
|
-
@classmethod
|
32
|
-
def get_schema(cls) -> Dict[str, Any]:
|
33
|
-
"""
|
34
|
-
Returns JSON schema for result validation.
|
35
|
-
|
36
|
-
Returns:
|
37
|
-
Dictionary with JSON schema
|
38
|
-
"""
|
39
|
-
return {
|
40
|
-
"type": "object",
|
41
|
-
"properties": {
|
42
|
-
"success": {"type": "boolean"},
|
43
|
-
"data": {
|
44
|
-
"type": "object",
|
45
|
-
"properties": {
|
46
|
-
"message": {"type": "string"},
|
47
|
-
"timestamp": {"type": "string", "format": "date-time"}
|
48
|
-
},
|
49
|
-
"required": ["message", "timestamp"]
|
50
|
-
},
|
51
|
-
"message": {"type": "string"}
|
52
|
-
},
|
53
|
-
"required": ["success", "data"]
|
54
|
-
}
|
55
|
-
|
56
|
-
|
57
|
-
class TimeService:
|
58
|
-
"""
|
59
|
-
Service for time-related operations.
|
60
|
-
|
61
|
-
This is a dependency that will be injected into the EchoCommand.
|
62
|
-
"""
|
63
|
-
|
64
|
-
def get_current_time(self) -> str:
|
65
|
-
"""
|
66
|
-
Get current time formatted as ISO string.
|
67
|
-
|
68
|
-
Returns:
|
69
|
-
Current time as ISO formatted string
|
70
|
-
"""
|
71
|
-
from datetime import datetime
|
72
|
-
return datetime.now().isoformat()
|
73
|
-
|
74
|
-
|
75
|
-
class EchoCommand(Command):
|
76
|
-
"""
|
77
|
-
Command that echoes back a message with timestamp.
|
78
|
-
|
79
|
-
This command demonstrates how to use dependency injection in commands
|
80
|
-
by accepting a service dependency in the constructor.
|
81
|
-
"""
|
82
|
-
|
83
|
-
# Command name for JSON-RPC endpoint
|
84
|
-
name = "echo_di"
|
85
|
-
# Command result class
|
86
|
-
result_class = EchoCommandResult
|
87
|
-
|
88
|
-
def __init__(self, time_service: TimeService):
|
89
|
-
"""
|
90
|
-
Initialize command with dependencies.
|
91
|
-
|
92
|
-
Args:
|
93
|
-
time_service: Service for getting the current time
|
94
|
-
"""
|
95
|
-
self.time_service = time_service
|
96
|
-
|
97
|
-
async def execute(self, message: str = "Hello, World!") -> CommandResult:
|
98
|
-
"""
|
99
|
-
Executes echo command.
|
100
|
-
|
101
|
-
Args:
|
102
|
-
message: Message to echo back
|
103
|
-
|
104
|
-
Returns:
|
105
|
-
Command execution result with message and timestamp
|
106
|
-
"""
|
107
|
-
timestamp = self.time_service.get_current_time()
|
108
|
-
return EchoCommandResult(message=message, timestamp=timestamp)
|
109
|
-
|
110
|
-
@classmethod
|
111
|
-
def get_schema(cls) -> Dict[str, Any]:
|
112
|
-
"""
|
113
|
-
Returns JSON schema for command parameters validation.
|
114
|
-
|
115
|
-
Returns:
|
116
|
-
Dictionary with JSON schema
|
117
|
-
"""
|
118
|
-
return {
|
119
|
-
"type": "object",
|
120
|
-
"properties": {
|
121
|
-
"message": {
|
122
|
-
"type": "string",
|
123
|
-
"description": "Message to echo back"
|
124
|
-
}
|
125
|
-
},
|
126
|
-
"additionalProperties": False
|
127
|
-
}
|
128
|
-
|
129
|
-
|
130
|
-
# Example of registering the command with dependency injection
|
131
|
-
def register_echo_command():
|
132
|
-
"""
|
133
|
-
Register echo command with dependencies.
|
134
|
-
|
135
|
-
This function shows how to:
|
136
|
-
1. Create a service dependency
|
137
|
-
2. Create a command instance with the dependency
|
138
|
-
3. Register the command instance in the registry
|
139
|
-
"""
|
140
|
-
from mcp_proxy_adapter.commands import registry, container
|
141
|
-
|
142
|
-
# Create and register service in the container
|
143
|
-
time_service = TimeService()
|
144
|
-
container.register("time_service", time_service)
|
145
|
-
|
146
|
-
# Create command with dependencies
|
147
|
-
echo_command = EchoCommand(time_service)
|
148
|
-
|
149
|
-
# Register command instance
|
150
|
-
registry.register(echo_command)
|
151
|
-
|
152
|
-
return echo_command
|
examples/commands/echo_result.py
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Module with result class for echo command.
|
3
|
-
"""
|
4
|
-
|
5
|
-
from typing import Any, Dict, ClassVar, Type
|
6
|
-
from pydantic import BaseModel, Field
|
7
|
-
|
8
|
-
from mcp_proxy_adapter.commands.result import CommandResult
|
9
|
-
|
10
|
-
|
11
|
-
class EchoResult(CommandResult, BaseModel):
|
12
|
-
"""
|
13
|
-
Result of echo command execution.
|
14
|
-
|
15
|
-
Attributes:
|
16
|
-
params (Dict[str, Any]): Parameters that were passed to the command.
|
17
|
-
"""
|
18
|
-
|
19
|
-
params: Dict[str, Any] = Field(..., description="Parameters that were passed to the command")
|
20
|
-
|
21
|
-
def to_dict(self) -> Dict[str, Any]:
|
22
|
-
"""
|
23
|
-
Converts result to dictionary for serialization.
|
24
|
-
|
25
|
-
Returns:
|
26
|
-
Dictionary with result data.
|
27
|
-
"""
|
28
|
-
return {
|
29
|
-
"params": self.params
|
30
|
-
}
|
31
|
-
|
32
|
-
@classmethod
|
33
|
-
def get_schema(cls) -> Dict[str, Any]:
|
34
|
-
"""
|
35
|
-
Returns JSON schema for result validation.
|
36
|
-
|
37
|
-
Returns:
|
38
|
-
Dictionary with JSON schema.
|
39
|
-
"""
|
40
|
-
return {
|
41
|
-
"type": "object",
|
42
|
-
"properties": {
|
43
|
-
"params": {
|
44
|
-
"type": "object",
|
45
|
-
"description": "Parameters that were passed to the command",
|
46
|
-
"additionalProperties": True
|
47
|
-
}
|
48
|
-
},
|
49
|
-
"required": ["params"]
|
50
|
-
}
|
51
|
-
|
52
|
-
@classmethod
|
53
|
-
def from_dict(cls, data: Dict[str, Any]) -> "EchoResult":
|
54
|
-
"""
|
55
|
-
Creates result instance from dictionary.
|
56
|
-
|
57
|
-
Args:
|
58
|
-
data: Dictionary with result data.
|
59
|
-
|
60
|
-
Returns:
|
61
|
-
EchoResult instance.
|
62
|
-
"""
|
63
|
-
return cls(
|
64
|
-
params=data.get("params", {})
|
65
|
-
)
|