mcp-proxy-adapter 3.1.4__py3-none-any.whl → 3.1.6__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.
- examples/check_vstl_schema.py +106 -0
- examples/patch_vstl_service.py +105 -0
- examples/patch_vstl_service_mcp.py +108 -0
- examples/test_package_3.1.4.py +4 -4
- mcp_proxy_adapter/api/app.py +21 -0
- mcp_proxy_adapter/commands/command_registry.py +15 -0
- mcp_proxy_adapter/commands/help_command.py +166 -71
- mcp_proxy_adapter/tests/commands/test_help_command.py +8 -5
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +4 -5
- mcp_proxy_adapter/tests/test_command_registry.py +37 -1
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-3.1.4.dist-info → mcp_proxy_adapter-3.1.6.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-3.1.4.dist-info → mcp_proxy_adapter-3.1.6.dist-info}/RECORD +16 -13
- {mcp_proxy_adapter-3.1.4.dist-info → mcp_proxy_adapter-3.1.6.dist-info}/WHEEL +1 -1
- {mcp_proxy_adapter-3.1.4.dist-info → mcp_proxy_adapter-3.1.6.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-3.1.4.dist-info → mcp_proxy_adapter-3.1.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,106 @@
|
|
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}")
|
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Скрипт для исправления ошибки 'name null is not defined' в сервисе VSTL.
|
4
|
+
|
5
|
+
Этот скрипт обходит проблему с обработкой null в сервисе vstl
|
6
|
+
при помощи модификации JSON-RPC запросов, чтобы заменять null на None.
|
7
|
+
|
8
|
+
Использование:
|
9
|
+
python patch_vstl_service.py
|
10
|
+
"""
|
11
|
+
|
12
|
+
import sys
|
13
|
+
import json
|
14
|
+
import requests
|
15
|
+
from typing import Dict, Any, Optional
|
16
|
+
|
17
|
+
# URL и заголовки для VSTL сервиса
|
18
|
+
VSTL_URL = "http://localhost:8000/cmd"
|
19
|
+
HEADERS = {"Content-Type": "application/json"}
|
20
|
+
|
21
|
+
def safe_call_vstl(command: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
|
22
|
+
"""
|
23
|
+
Безопасно вызывает команду в сервисе VSTL, обрабатывая null значения.
|
24
|
+
|
25
|
+
Args:
|
26
|
+
command: Имя команды
|
27
|
+
params: Параметры для команды
|
28
|
+
|
29
|
+
Returns:
|
30
|
+
Dict[str, Any]: Ответ от сервиса
|
31
|
+
"""
|
32
|
+
# Обработка null значений - заменяем null на None для Python
|
33
|
+
safe_params = {}
|
34
|
+
if params:
|
35
|
+
for key, value in params.items():
|
36
|
+
if value == "null" or value == "none":
|
37
|
+
safe_params[key] = None
|
38
|
+
else:
|
39
|
+
safe_params[key] = value
|
40
|
+
|
41
|
+
# Безопасно сериализуем параметры, чтобы null значения были корректно обработаны
|
42
|
+
payload = {
|
43
|
+
"jsonrpc": "2.0",
|
44
|
+
"method": command,
|
45
|
+
"params": safe_params or {},
|
46
|
+
"id": 1
|
47
|
+
}
|
48
|
+
|
49
|
+
# Отправляем запрос
|
50
|
+
response = requests.post(VSTL_URL, json=payload, headers=HEADERS)
|
51
|
+
return response.json()
|
52
|
+
|
53
|
+
def test_vstl_commands():
|
54
|
+
"""
|
55
|
+
Тестирует различные команды в сервисе VSTL с безопасной обработкой null.
|
56
|
+
"""
|
57
|
+
print("=== Тестирование команд VSTL с патчем для обработки null ===\n")
|
58
|
+
|
59
|
+
# Проверяем команду health
|
60
|
+
print("1. Команда health:")
|
61
|
+
response = safe_call_vstl("health", {})
|
62
|
+
print(f"Ответ: {json.dumps(response, indent=2)}\n")
|
63
|
+
|
64
|
+
# Проверяем команду help без параметров
|
65
|
+
print("2. Команда help без параметров:")
|
66
|
+
response = safe_call_vstl("help", {})
|
67
|
+
print(f"Ответ: {json.dumps(response, indent=2)}")
|
68
|
+
|
69
|
+
# Если команда help сработала, выведем список всех доступных команд
|
70
|
+
if response.get("result") and not response.get("error"):
|
71
|
+
commands_info = response["result"].get("commands", {})
|
72
|
+
print(f"\nДоступные команды ({len(commands_info)}):")
|
73
|
+
for cmd_name, cmd_info in commands_info.items():
|
74
|
+
print(f" - {cmd_name}: {cmd_info.get('summary', 'Нет описания')}")
|
75
|
+
|
76
|
+
# Проверяем команду help с параметром cmdname
|
77
|
+
print("\n3. Команда help с параметром cmdname:")
|
78
|
+
response = safe_call_vstl("help", {"cmdname": "health"})
|
79
|
+
print(f"Ответ: {json.dumps(response, indent=2)}\n")
|
80
|
+
|
81
|
+
# Проверяем команду config
|
82
|
+
print("4. Команда config:")
|
83
|
+
response = safe_call_vstl("config", {"operation": "get"})
|
84
|
+
print(f"Ответ: {json.dumps(response, indent=2)}\n")
|
85
|
+
|
86
|
+
# Выводим рекомендации по полному исправлению
|
87
|
+
print("\n=== Рекомендации по полному исправлению проблемы с null в VSTL ===")
|
88
|
+
print("""
|
89
|
+
1. Проверьте исходный код сервиса VSTL на наличие использования переменной 'null'
|
90
|
+
без её объявления (обратите внимание на файл help_command.py)
|
91
|
+
|
92
|
+
2. Замените все использования JavaScript-стиля null на Python None:
|
93
|
+
- Поиск: if value == null
|
94
|
+
- Замена: if value is None
|
95
|
+
|
96
|
+
3. Обновите сервис до последней версии mcp_proxy_adapter 3.1.6 и перезапустите
|
97
|
+
|
98
|
+
4. Если это невозможно, используйте этот скрипт как промежуточное решение,
|
99
|
+
чтобы безопасно вызывать команды VSTL с корректной обработкой null.
|
100
|
+
|
101
|
+
5. Внесите исправления в метод validate_params, как показано в fix_vstl_help.py
|
102
|
+
""")
|
103
|
+
|
104
|
+
if __name__ == "__main__":
|
105
|
+
test_vstl_commands()
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Скрипт для исправления ошибки 'name null is not defined' в сервисе VSTL через MCP Proxy API.
|
4
|
+
|
5
|
+
Этот скрипт демонстрирует как обойти проблему с null в сервисе vstl,
|
6
|
+
используя стандартные средства MCP Proxy API.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import os
|
10
|
+
import sys
|
11
|
+
import json
|
12
|
+
import subprocess
|
13
|
+
from typing import Dict, Any, Optional
|
14
|
+
|
15
|
+
def call_vstl_command(command: str, params: Optional[Dict[str, Any]] = None):
|
16
|
+
"""
|
17
|
+
Вызывает команду vstl через MCP Proxy API.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
command: Название команды
|
21
|
+
params: Параметры команды
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
Результат выполнения команды
|
25
|
+
"""
|
26
|
+
# Формируем параметры для команды mcp_MCP-Proxy_vstl
|
27
|
+
if params is None:
|
28
|
+
params = {}
|
29
|
+
|
30
|
+
# Сериализуем параметры в JSON
|
31
|
+
params_json = json.dumps(params)
|
32
|
+
|
33
|
+
# Формируем команду для вызова MCP Proxy API
|
34
|
+
cmd = [
|
35
|
+
"curl", "-s",
|
36
|
+
"-X", "POST",
|
37
|
+
"-H", "Content-Type: application/json",
|
38
|
+
"-d", f'{{"jsonrpc":"2.0","method":"{command}","params":{params_json},"id":1}}',
|
39
|
+
"http://localhost:8000/api/vstl"
|
40
|
+
]
|
41
|
+
|
42
|
+
# Выполняем команду
|
43
|
+
try:
|
44
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
45
|
+
# Парсим результат как JSON
|
46
|
+
return json.loads(result.stdout)
|
47
|
+
except subprocess.CalledProcessError as e:
|
48
|
+
print(f"Ошибка выполнения команды: {e}")
|
49
|
+
print(f"STDOUT: {e.stdout}")
|
50
|
+
print(f"STDERR: {e.stderr}")
|
51
|
+
return {"error": str(e)}
|
52
|
+
except json.JSONDecodeError as e:
|
53
|
+
print(f"Ошибка декодирования JSON: {e}")
|
54
|
+
print(f"Ответ: {result.stdout}")
|
55
|
+
return {"error": "Неверный формат JSON в ответе"}
|
56
|
+
|
57
|
+
def test_vstl_commands():
|
58
|
+
"""
|
59
|
+
Тестирует различные команды vstl с обходом проблемы null.
|
60
|
+
"""
|
61
|
+
print("=== Тестирование команд VSTL через MCP Proxy API ===\n")
|
62
|
+
|
63
|
+
# Проверяем команду health
|
64
|
+
print("1. Команда health:")
|
65
|
+
response = call_vstl_command("health", {})
|
66
|
+
print(f"Ответ: {json.dumps(response, indent=2)}\n")
|
67
|
+
|
68
|
+
# Проверяем команду help без параметров
|
69
|
+
print("2. Команда help без параметров:")
|
70
|
+
response = call_vstl_command("help", {})
|
71
|
+
print(f"Ответ: {json.dumps(response, indent=2)}")
|
72
|
+
|
73
|
+
# Если есть ошибка в команде help без параметров, попробуем еще несколько вариантов
|
74
|
+
if "error" in response:
|
75
|
+
print("\n2.1. Попытка обойти ошибку - вызов help с корректными параметрами:")
|
76
|
+
response = call_vstl_command("help", {"cmdname": None})
|
77
|
+
print(f"Ответ: {json.dumps(response, indent=2)}")
|
78
|
+
|
79
|
+
# Проверяем команду help с параметром cmdname
|
80
|
+
print("\n3. Команда help с параметром cmdname:")
|
81
|
+
response = call_vstl_command("help", {"cmdname": "health"})
|
82
|
+
print(f"Ответ: {json.dumps(response, indent=2)}\n")
|
83
|
+
|
84
|
+
# Проверяем команду config
|
85
|
+
print("4. Команда config:")
|
86
|
+
response = call_vstl_command("config", {"operation": "get"})
|
87
|
+
print(f"Ответ: {json.dumps(response, indent=2)}\n")
|
88
|
+
|
89
|
+
# Выводим рекомендации по исправлению
|
90
|
+
print("\n=== Рекомендации по исправлению проблемы с null в VSTL ===")
|
91
|
+
print("""
|
92
|
+
1. Проблема с обработкой null в JavaScript-совместимых API - это распространенная ошибка.
|
93
|
+
В JavaScript null - это ключевое слово, а в Python - это None.
|
94
|
+
|
95
|
+
2. Для полного решения проблемы необходимо исправить реализацию сервиса VSTL:
|
96
|
+
- Найти в коде места, где используется 'null' как переменная
|
97
|
+
- Заменить на корректное использование None
|
98
|
+
- Добавить к аргументам метода execute в help_command.py параметр **kwargs
|
99
|
+
- Обновить метод validate_params для обработки строковых представлений null
|
100
|
+
|
101
|
+
3. До исправления сервера можно использовать следующие обходные пути:
|
102
|
+
- Использовать MCP Proxy API с корректными значениями параметров (None вместо null)
|
103
|
+
- Использовать промежуточный слой, который будет преобразовывать запросы
|
104
|
+
- Избегать отправки параметров null/None в командах, где это возможно
|
105
|
+
""")
|
106
|
+
|
107
|
+
if __name__ == "__main__":
|
108
|
+
test_vstl_commands()
|
examples/test_package_3.1.4.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
"""
|
3
|
-
Скрипт для проверки работы улучшенной обработки null в версии 3.1.
|
3
|
+
Скрипт для проверки работы улучшенной обработки null в версии 3.1.6.
|
4
4
|
|
5
5
|
Этот скрипт:
|
6
|
-
1. Проверяет, что версия пакета 3.1.
|
6
|
+
1. Проверяет, что версия пакета 3.1.6
|
7
7
|
2. Тестирует улучшенный метод validate_params
|
8
8
|
3. Проверяет, что команда help правильно обрабатывает null значения
|
9
9
|
"""
|
@@ -26,7 +26,7 @@ def check_version():
|
|
26
26
|
"""
|
27
27
|
Проверяет версию установленного пакета mcp_proxy_adapter.
|
28
28
|
"""
|
29
|
-
expected_version = "3.1.
|
29
|
+
expected_version = "3.1.6"
|
30
30
|
|
31
31
|
print(f"\n=== Проверка версии ===")
|
32
32
|
print(f"Установленная версия: {__version__}")
|
@@ -146,7 +146,7 @@ def main():
|
|
146
146
|
"""
|
147
147
|
Основная функция для запуска тестов.
|
148
148
|
"""
|
149
|
-
print("=== Проверка MCP Proxy Adapter 3.1.
|
149
|
+
print("=== Проверка MCP Proxy Adapter 3.1.6 ===")
|
150
150
|
|
151
151
|
# Проверяем версию пакета
|
152
152
|
version_ok = check_version()
|
mcp_proxy_adapter/api/app.py
CHANGED
@@ -200,6 +200,27 @@ def create_app() -> FastAPI:
|
|
200
200
|
"error": e.to_dict()
|
201
201
|
}
|
202
202
|
)
|
203
|
+
except NotFoundError as e:
|
204
|
+
# Специальная обработка для help-команды: возвращаем result с пустым commands и error
|
205
|
+
if command_name == "help":
|
206
|
+
return {
|
207
|
+
"result": {
|
208
|
+
"success": False,
|
209
|
+
"commands": {},
|
210
|
+
"error": str(e),
|
211
|
+
"note": "To get detailed information about a specific command, call help with parameter: POST /cmd {\"command\": \"help\", \"params\": {\"cmdname\": \"<command_name>\"}}"
|
212
|
+
}
|
213
|
+
}
|
214
|
+
# Для остальных команд — стандартная ошибка
|
215
|
+
return JSONResponse(
|
216
|
+
status_code=200,
|
217
|
+
content={
|
218
|
+
"error": {
|
219
|
+
"code": e.code,
|
220
|
+
"message": str(e)
|
221
|
+
}
|
222
|
+
}
|
223
|
+
)
|
203
224
|
|
204
225
|
except json.JSONDecodeError:
|
205
226
|
req_logger.error("JSON decode error")
|
@@ -1,5 +1,20 @@
|
|
1
1
|
"""
|
2
2
|
Module for registering and managing commands.
|
3
|
+
|
4
|
+
Example: Registering a command instance (for dependency injection)
|
5
|
+
---------------------------------------------------------------
|
6
|
+
|
7
|
+
.. code-block:: python
|
8
|
+
|
9
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
10
|
+
from my_commands import MyCommand
|
11
|
+
|
12
|
+
# Suppose MyCommand requires a service dependency
|
13
|
+
service = MyService()
|
14
|
+
my_command_instance = MyCommand(service=service)
|
15
|
+
registry.register(my_command_instance)
|
16
|
+
|
17
|
+
# Now, when the command is executed, the same instance (with dependencies) will be used
|
3
18
|
"""
|
4
19
|
|
5
20
|
import importlib
|
@@ -3,61 +3,112 @@ Module with help command implementation.
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
from typing import Dict, Any, Optional
|
6
|
+
import logging
|
7
|
+
import traceback
|
6
8
|
|
7
9
|
from mcp_proxy_adapter.commands.base import Command
|
8
10
|
from mcp_proxy_adapter.commands.result import CommandResult
|
9
11
|
from mcp_proxy_adapter.commands.command_registry import registry
|
10
12
|
from mcp_proxy_adapter.core.errors import NotFoundError
|
11
13
|
|
14
|
+
# Добавляем логирование
|
15
|
+
logger = logging.getLogger("mcp_proxy_adapter.commands.help_command")
|
16
|
+
|
12
17
|
|
13
18
|
class HelpResult(CommandResult):
|
14
19
|
"""
|
15
20
|
Result of the help command execution.
|
16
21
|
"""
|
17
|
-
|
22
|
+
|
18
23
|
def __init__(self, commands_info: Optional[Dict[str, Any]] = None, command_info: Optional[Dict[str, Any]] = None):
|
19
24
|
"""
|
20
25
|
Initialize help command result.
|
21
|
-
|
26
|
+
|
22
27
|
Args:
|
23
28
|
commands_info: Information about all commands (for request without parameters)
|
24
29
|
command_info: Information about a specific command (for request with cmdname parameter)
|
25
30
|
"""
|
31
|
+
logger.debug(f"HelpResult.__init__: commands_info={commands_info is not None}, command_info={command_info is not None}")
|
26
32
|
self.commands_info = commands_info
|
27
33
|
self.command_info = command_info
|
28
|
-
|
34
|
+
|
29
35
|
def to_dict(self) -> Dict[str, Any]:
|
30
36
|
"""
|
31
37
|
Convert result to dictionary.
|
32
|
-
|
38
|
+
|
33
39
|
Returns:
|
34
40
|
Dict[str, Any]: Result as dictionary
|
35
41
|
"""
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
try:
|
43
|
+
logger.debug(f"HelpResult.to_dict: command_info={self.command_info is not None}, commands_info={self.commands_info is not None}")
|
44
|
+
|
45
|
+
# Защита от None для self.command_info
|
46
|
+
if self.command_info is not None:
|
47
|
+
logger.debug(f"HelpResult.to_dict: returning command_info for {self.command_info.get('name', 'unknown')}")
|
48
|
+
# Делаем безопасное получение всех полей с дефолтными значениями
|
49
|
+
return {
|
50
|
+
"cmdname": self.command_info.get("name", "unknown"),
|
51
|
+
"info": {
|
52
|
+
"description": self.command_info.get("description", ""),
|
53
|
+
"summary": self.command_info.get("summary", ""),
|
54
|
+
"params": self.command_info.get("params", {}),
|
55
|
+
"examples": self.command_info.get("examples", [])
|
56
|
+
}
|
44
57
|
}
|
58
|
+
|
59
|
+
# Защита от None для self.commands_info
|
60
|
+
if self.commands_info is None:
|
61
|
+
logger.warning("HelpResult.to_dict: commands_info is None, создаем пустой результат")
|
62
|
+
# Возвращаем пустой список команд вместо ошибки
|
63
|
+
return {
|
64
|
+
"tool_info": {
|
65
|
+
"name": "MCP-Proxy API Service",
|
66
|
+
"description": "JSON-RPC API for microservice command execution",
|
67
|
+
"version": "1.0.0"
|
68
|
+
},
|
69
|
+
"help_usage": {
|
70
|
+
"description": "Get information about commands",
|
71
|
+
"examples": [
|
72
|
+
{"command": "help", "description": "List of all available commands"},
|
73
|
+
{"command": "help", "params": {"cmdname": "command_name"}, "description": "Get detailed information about a specific command"}
|
74
|
+
]
|
75
|
+
},
|
76
|
+
"commands": {},
|
77
|
+
"total": 0,
|
78
|
+
"note": "To get detailed information about a specific command, call help with parameter: POST /cmd {\"command\": \"help\", \"params\": {\"cmdname\": \"<command_name>\"}}"
|
79
|
+
}
|
80
|
+
|
81
|
+
# For list of all commands, return as is (already formatted)
|
82
|
+
logger.debug(f"HelpResult.to_dict: processing commands_info with {len(self.commands_info.get('commands', {}))} commands")
|
83
|
+
result = self.commands_info.copy()
|
84
|
+
|
85
|
+
# Add total count and note about usage
|
86
|
+
commands = result.get("commands", {})
|
87
|
+
result["total"] = len(commands)
|
88
|
+
result["note"] = "To get detailed information about a specific command, call help with parameter: POST /cmd {\"command\": \"help\", \"params\": {\"cmdname\": \"<command_name>\"}}"
|
89
|
+
|
90
|
+
logger.debug(f"HelpResult.to_dict: returning result with {result['total']} commands")
|
91
|
+
return result
|
92
|
+
except Exception as e:
|
93
|
+
logger.error(f"Ошибка в HelpResult.to_dict: {e}")
|
94
|
+
logger.debug(f"Трассировка: {traceback.format_exc()}")
|
95
|
+
# В случае неожиданной ошибки возвращаем базовый ответ вместо ошибки
|
96
|
+
return {
|
97
|
+
"tool_info": {
|
98
|
+
"name": "MCP-Proxy API Service",
|
99
|
+
"description": "JSON-RPC API for microservice command execution",
|
100
|
+
"version": "1.0.0"
|
101
|
+
},
|
102
|
+
"commands": {},
|
103
|
+
"total": 0,
|
104
|
+
"error": str(e)
|
45
105
|
}
|
46
|
-
|
47
|
-
# For list of all commands, return as is (already formatted)
|
48
|
-
result = self.commands_info.copy()
|
49
|
-
|
50
|
-
# Add total count and note about usage
|
51
|
-
result["total"] = len(result["commands"])
|
52
|
-
result["note"] = "To get detailed information about a specific command, call help with parameter: POST /cmd {\"command\": \"help\", \"params\": {\"cmdname\": \"<command_name>\"}}. Only 'cmdname' parameter is supported."
|
53
|
-
|
54
|
-
return result
|
55
|
-
|
106
|
+
|
56
107
|
@classmethod
|
57
108
|
def get_schema(cls) -> Dict[str, Any]:
|
58
109
|
"""
|
59
110
|
Get JSON schema for result validation.
|
60
|
-
|
111
|
+
|
61
112
|
Returns:
|
62
113
|
Dict[str, Any]: JSON schema
|
63
114
|
"""
|
@@ -114,72 +165,116 @@ class HelpCommand(Command):
|
|
114
165
|
"""
|
115
166
|
Command for getting help information about available commands.
|
116
167
|
"""
|
117
|
-
|
168
|
+
|
118
169
|
name = "help"
|
119
170
|
result_class = HelpResult
|
120
|
-
|
171
|
+
|
121
172
|
async def execute(self, cmdname: Optional[str] = None, **kwargs) -> HelpResult:
|
122
173
|
"""
|
123
174
|
Execute help command.
|
124
|
-
|
175
|
+
|
125
176
|
Args:
|
126
177
|
cmdname: Name of the command to get information about (optional)
|
127
178
|
**kwargs: Any additional parameters (will be ignored)
|
128
|
-
|
179
|
+
|
129
180
|
Returns:
|
130
181
|
HelpResult: Help command result
|
131
|
-
|
182
|
+
|
132
183
|
Raises:
|
133
184
|
NotFoundError: If specified command not found
|
134
185
|
"""
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
186
|
+
logger.debug(f"HelpCommand.execute начало: cmdname={cmdname}, kwargs={kwargs}")
|
187
|
+
|
188
|
+
try:
|
189
|
+
# Handle case when cmdname is provided
|
190
|
+
if cmdname is not None and cmdname != "":
|
191
|
+
logger.debug(f"Обработка запроса для конкретной команды: {cmdname}")
|
192
|
+
try:
|
193
|
+
# Get command metadata from registry
|
194
|
+
command_metadata = registry.get_command_metadata(cmdname)
|
195
|
+
logger.debug(f"Получены метаданные для команды {cmdname}")
|
196
|
+
return HelpResult(command_info=command_metadata)
|
197
|
+
except NotFoundError:
|
198
|
+
logger.warning(f"Команда '{cmdname}' не найдена")
|
199
|
+
# Получаем список всех команд
|
200
|
+
all_commands = list(registry.get_all_metadata().keys())
|
201
|
+
if all_commands:
|
202
|
+
example_cmd = all_commands[0]
|
203
|
+
example = {
|
204
|
+
"command": "help",
|
205
|
+
"params": {"cmdname": example_cmd}
|
206
|
+
}
|
207
|
+
note = f"Use help with an existing command name to get detailed info. For example: help with cmdname '{example_cmd}'. To list all commands: call help without parameters."
|
208
|
+
else:
|
209
|
+
example = {"command": "help"}
|
210
|
+
note = "No commands registered. To list all commands: call help without parameters."
|
211
|
+
return HelpResult(commands_info={
|
212
|
+
"commands": {},
|
213
|
+
"error": f"Command '{cmdname}' not found",
|
214
|
+
"example": example,
|
215
|
+
"note": note
|
216
|
+
})
|
217
|
+
|
218
|
+
# Otherwise, return information about all available commands
|
219
|
+
logger.debug("Обработка запроса для всех команд")
|
220
|
+
|
221
|
+
# Get metadata for all commands
|
222
|
+
all_metadata = registry.get_all_metadata()
|
223
|
+
logger.debug(f"Получены метаданные для {len(all_metadata)} команд")
|
224
|
+
|
225
|
+
# Prepare response format with tool metadata
|
226
|
+
result = {
|
227
|
+
"tool_info": {
|
228
|
+
"name": "MCP-Proxy API Service",
|
229
|
+
"description": "JSON-RPC API for microservice command execution",
|
230
|
+
"version": "1.0.0"
|
231
|
+
},
|
232
|
+
"help_usage": {
|
233
|
+
"description": "Get information about commands",
|
234
|
+
"examples": [
|
235
|
+
{"command": "help", "description": "List of all available commands"},
|
236
|
+
{"command": "help", "params": {"cmdname": "command_name"}, "description": "Get detailed information about a specific command"}
|
237
|
+
]
|
238
|
+
},
|
239
|
+
"commands": {}
|
174
240
|
}
|
175
|
-
|
176
|
-
|
177
|
-
|
241
|
+
|
242
|
+
# Add brief information about commands
|
243
|
+
for name, metadata in all_metadata.items():
|
244
|
+
try:
|
245
|
+
logger.debug(f"Обработка метаданных команды {name}")
|
246
|
+
# Безопасное получение параметров с проверкой на наличие ключей
|
247
|
+
result["commands"][name] = {
|
248
|
+
"summary": metadata.get("summary", ""),
|
249
|
+
"params_count": len(metadata.get("params", {}))
|
250
|
+
}
|
251
|
+
except Exception as e:
|
252
|
+
logger.error(f"Ошибка при обработке метаданных команды {name}: {e}")
|
253
|
+
logger.debug(f"Метаданные команды {name}: {metadata}")
|
254
|
+
# Пропускаем проблемную команду
|
255
|
+
continue
|
256
|
+
|
257
|
+
logger.debug(f"HelpCommand.execute завершение: возвращаем результат с {len(result['commands'])} командами")
|
258
|
+
return HelpResult(commands_info=result)
|
259
|
+
except Exception as e:
|
260
|
+
logger.error(f"Неожиданная ошибка в HelpCommand.execute: {e}")
|
261
|
+
logger.debug(f"Трассировка: {traceback.format_exc()}")
|
262
|
+
# В случае неожиданной ошибки возвращаем пустой результат вместо ошибки
|
263
|
+
return HelpResult(commands_info={
|
264
|
+
"tool_info": {
|
265
|
+
"name": "MCP-Proxy API Service",
|
266
|
+
"description": "JSON-RPC API for microservice command execution",
|
267
|
+
"version": "1.0.0"
|
268
|
+
},
|
269
|
+
"commands": {},
|
270
|
+
"error": str(e)
|
271
|
+
})
|
272
|
+
|
178
273
|
@classmethod
|
179
274
|
def get_schema(cls) -> Dict[str, Any]:
|
180
275
|
"""
|
181
276
|
Get JSON schema for command parameters validation.
|
182
|
-
|
277
|
+
|
183
278
|
Returns:
|
184
279
|
Dict[str, Any]: JSON schema
|
185
280
|
"""
|
@@ -97,12 +97,15 @@ async def test_help_command_with_invalid_cmdname(mock_registry):
|
|
97
97
|
# Setup mocks
|
98
98
|
mock_registry.get_command_metadata.side_effect = NotFoundError("Command not found")
|
99
99
|
|
100
|
-
# Execute command and check
|
100
|
+
# Execute command and check result fields
|
101
101
|
command = HelpCommand()
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
assert "
|
102
|
+
result = await command.execute(cmdname="non_existent")
|
103
|
+
result_dict = result.to_dict()
|
104
|
+
assert "error" in result_dict
|
105
|
+
assert "example" in result_dict
|
106
|
+
assert "note" in result_dict
|
107
|
+
assert result_dict["error"].startswith("Command")
|
108
|
+
assert result_dict["example"]["command"] == "help"
|
106
109
|
|
107
110
|
|
108
111
|
def test_help_result_schema():
|
@@ -92,12 +92,11 @@ def test_cmd_help_unknown_command(client):
|
|
92
92
|
assert "result" in response.json()
|
93
93
|
result = response.json()["result"]
|
94
94
|
|
95
|
-
assert "success" in result and result["success"] is False
|
96
95
|
assert "error" in result
|
97
|
-
|
98
|
-
|
99
|
-
assert
|
100
|
-
assert "
|
96
|
+
assert "example" in result
|
97
|
+
assert "note" in result
|
98
|
+
assert result["error"].startswith("Command")
|
99
|
+
assert result["example"]["command"] == "help"
|
101
100
|
|
102
101
|
|
103
102
|
def test_cmd_unknown_command(client):
|
@@ -242,4 +242,40 @@ def test_clear_registry():
|
|
242
242
|
|
243
243
|
# Clear registry
|
244
244
|
registry.clear()
|
245
|
-
assert len(registry._commands) == 0
|
245
|
+
assert len(registry._commands) == 0
|
246
|
+
|
247
|
+
|
248
|
+
def test_register_command_instance():
|
249
|
+
"""Test registering a command instance (with dependencies)."""
|
250
|
+
registry = CommandRegistry()
|
251
|
+
|
252
|
+
class Service:
|
253
|
+
def __init__(self, value):
|
254
|
+
self.value = value
|
255
|
+
|
256
|
+
class CommandWithDependency(Command):
|
257
|
+
name = "command_with_dep"
|
258
|
+
result_class = MockResult
|
259
|
+
def __init__(self, service: Service):
|
260
|
+
self.service = service
|
261
|
+
async def execute(self, **kwargs):
|
262
|
+
# Return the value from the injected service
|
263
|
+
result = MockResult()
|
264
|
+
result.service_value = self.service.value
|
265
|
+
return result
|
266
|
+
|
267
|
+
service = Service(value=42)
|
268
|
+
command_instance = CommandWithDependency(service=service)
|
269
|
+
registry.register(command_instance)
|
270
|
+
|
271
|
+
# Проверяем, что экземпляр зарегистрирован
|
272
|
+
assert registry.has_instance("command_with_dep")
|
273
|
+
# Проверяем, что get_command_instance возвращает именно этот экземпляр
|
274
|
+
assert registry.get_command_instance("command_with_dep") is command_instance
|
275
|
+
# Проверяем, что execute использует внедрённый сервис
|
276
|
+
import asyncio
|
277
|
+
result = asyncio.run(
|
278
|
+
registry.get_command_instance("command_with_dep").execute()
|
279
|
+
)
|
280
|
+
assert hasattr(result, "service_value")
|
281
|
+
assert result.service_value == 42
|
mcp_proxy_adapter/version.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
examples/__init__.py,sha256=sLYNpeoiE-X5q7fmJb7NFMmhiIn0543mgJj16q1qmk0,593
|
2
|
+
examples/check_vstl_schema.py,sha256=s-VVoY8ysuvVr64JAX6uvxuwjEB7FjbJf0ek7XYc1Nc,4320
|
2
3
|
examples/fix_vstl_help.py,sha256=GvFepKbCD-a2O2LEflMGeXnsgNMUNfNezPFU6QB_7tI,5208
|
4
|
+
examples/patch_vstl_service.py,sha256=MU-PxZ9gAQx-gT0tyxoWIswDbdV4cYd-r-T9gq4aziw,4715
|
5
|
+
examples/patch_vstl_service_mcp.py,sha256=jiMKzx8hANFVtM0Yv-DJbThwM4r81z9dslF_v9tkAf4,5254
|
3
6
|
examples/server.py,sha256=gnRTE_k7C0A255dLyaJWyA4YU0H6Elc7osr_JQvsQhQ,2286
|
4
7
|
examples/simple_server.py,sha256=Bkczmz5Qs473xJ0_AJjBpqWT-oWctwED98A067z05zQ,3768
|
5
|
-
examples/test_package_3.1.4.py,sha256=
|
8
|
+
examples/test_package_3.1.4.py,sha256=GZZANEIrZkw0gfsFK-PKi4lGZ6Fen25RFHSHrOOhR4w,7180
|
6
9
|
examples/test_server.py,sha256=cKWJ4tlHqZsRKyeuXbZ1dQ7TU9riJWcDan__wK7YH_Y,3729
|
7
10
|
examples/tool_description_example.py,sha256=blamrx_1oHCG4NnvIiYnQxphAEDqb7-TALPALJFj51s,3280
|
8
11
|
examples/anti_patterns/README.md,sha256=1-Hby6Wf3kAC0XOV_jOvuHL-kmTypWOUfE_rEU3Knu8,2045
|
@@ -52,9 +55,9 @@ mcp_proxy_adapter/config.py,sha256=MjgZAld6TiD0F5oCyEaJhYhfEXVZxc5G5ke2SLKCV9A,5
|
|
52
55
|
mcp_proxy_adapter/custom_openapi.py,sha256=tAE289B76nUdd2tjbiyow2Jftj0Yd-A8I2ndTD6R-5c,11706
|
53
56
|
mcp_proxy_adapter/openapi.py,sha256=jyl5EPXcFhzFKEEMXxHeqF1U-SsYvtdlaKGU2QrekpU,13889
|
54
57
|
mcp_proxy_adapter/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
-
mcp_proxy_adapter/version.py,sha256=
|
58
|
+
mcp_proxy_adapter/version.py,sha256=VRQ07cLW2F_OHDoYAsBuYZHDoj1M-ztVO8Joii9m1Iw,71
|
56
59
|
mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
|
-
mcp_proxy_adapter/api/app.py,sha256=
|
60
|
+
mcp_proxy_adapter/api/app.py,sha256=TdsZjAwdMr_tYGjmmH3D2voVmQOU_Lw9raKbbYhXkk0,15424
|
58
61
|
mcp_proxy_adapter/api/handlers.py,sha256=lc_4eakQgQVlnGjnVkOY-mIMkfyLk4iRfwdrWTyvuvM,7194
|
59
62
|
mcp_proxy_adapter/api/schemas.py,sha256=xOmiSwHaapY6myEFnLu7o-LWVPM7vwmLYZXFo2c6NfE,12381
|
60
63
|
mcp_proxy_adapter/api/tool_integration.py,sha256=mQNFiCkd4plY_A3fkG6auaM8D_1XiC9Jxp4Zrm1ngYE,10161
|
@@ -68,11 +71,11 @@ mcp_proxy_adapter/api/middleware/performance.py,sha256=dHBxTF43LEGXMKHMH3A8ybKmw
|
|
68
71
|
mcp_proxy_adapter/api/middleware/rate_limit.py,sha256=DIv_-ZUVmL-jEo_A5BlfnasZf25zT84AiIJDUUnXkpM,5041
|
69
72
|
mcp_proxy_adapter/commands/__init__.py,sha256=bHZZcVYkXVL9g-YZOnWkHOxSP2WzT-I4_OleYycQhbw,610
|
70
73
|
mcp_proxy_adapter/commands/base.py,sha256=lKKoN_9tJYIeOFKgQRGwWZHy_EvWP8bVB1EhIouTbi0,13740
|
71
|
-
mcp_proxy_adapter/commands/command_registry.py,sha256=
|
74
|
+
mcp_proxy_adapter/commands/command_registry.py,sha256=3KNmG1Blg1UrThZNU3vGj_2I4ZTFBjUgYZmk7QBOb4w,10998
|
72
75
|
mcp_proxy_adapter/commands/config_command.py,sha256=-Z6BGaEQTf859l56zZpHYBeZFeIVdpMYybDrd7LOPIg,3553
|
73
76
|
mcp_proxy_adapter/commands/dependency_container.py,sha256=Uz9OPRAUZN7tsVrMVgXgPQcsRD2N-e2Ixg9XarPOlnY,3410
|
74
77
|
mcp_proxy_adapter/commands/health_command.py,sha256=_tzxHwB_8vo53VBC6HnBv5fSfZL1pEuwlbrCcy_K78c,4087
|
75
|
-
mcp_proxy_adapter/commands/help_command.py,sha256=
|
78
|
+
mcp_proxy_adapter/commands/help_command.py,sha256=dfqNt1h2H6vQJ9rLySWa_-0-QzesnN-Mgx0cz-uFlIo,13051
|
76
79
|
mcp_proxy_adapter/commands/result.py,sha256=2WjftiAuhlyzOKmPJlQHo_b08ZCzWoK7cquUHFLVE-E,5534
|
77
80
|
mcp_proxy_adapter/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
78
81
|
mcp_proxy_adapter/core/errors.py,sha256=s34OxiIR4NCJu_pYSigKXqrIvRjUUK2OWw0X4dpDjIA,5151
|
@@ -86,7 +89,7 @@ mcp_proxy_adapter/tests/test_api_endpoints.py,sha256=ePtWCf0szD1JeY9WdHAhcKnuOzo
|
|
86
89
|
mcp_proxy_adapter/tests/test_api_handlers.py,sha256=LeHO0o6eCxan6mt_8ZkUwSbeY7qYfoYMJ-bT_sSgdxc,11011
|
87
90
|
mcp_proxy_adapter/tests/test_base_command.py,sha256=nSIi_mfjux8TL--65pMBfyg91EiLjJhI2P_ASWqyW-U,3779
|
88
91
|
mcp_proxy_adapter/tests/test_batch_requests.py,sha256=9-gvhPq48AcEwGlhwgn3DWNhpleLA0f4luZNYMrqlXY,4103
|
89
|
-
mcp_proxy_adapter/tests/test_command_registry.py,sha256=
|
92
|
+
mcp_proxy_adapter/tests/test_command_registry.py,sha256=ywi5gM7D7NHcNOkdwXOgpJqHjwGADZEaB3ueM3nR0gM,7683
|
90
93
|
mcp_proxy_adapter/tests/test_config.py,sha256=i4YbFhB3WI1wWKCxkG6l-UpFv2LAbhh4hmGipmYG1d0,3928
|
91
94
|
mcp_proxy_adapter/tests/test_utils.py,sha256=K8DqdWDAV-cXjjeykehHpG5phfq5ydu2HLJzaAL282Y,1653
|
92
95
|
mcp_proxy_adapter/tests/api/__init__.py,sha256=QzjeBIhrRLqfUKYmxVSCbMOoni5MAXgyAx9HxxB6JRs,27
|
@@ -95,11 +98,11 @@ mcp_proxy_adapter/tests/api/test_middleware.py,sha256=3Rgc09VJ7JG6_06oIgAVq6u7qJ
|
|
95
98
|
mcp_proxy_adapter/tests/commands/__init__.py,sha256=DZxhtyr__AleyXN1s8Ef887tK5nsoHKfW4QXyzLaP0E,36
|
96
99
|
mcp_proxy_adapter/tests/commands/test_config_command.py,sha256=ud0Y57xUhFiyrUKDyA0eBZ8IOKiGDpioijtwY-detC4,6522
|
97
100
|
mcp_proxy_adapter/tests/commands/test_echo_command.py,sha256=c2dmqfx3ZfvDedy5vuxArFv7iHsReepMmD2Lchg4l3E,3437
|
98
|
-
mcp_proxy_adapter/tests/commands/test_help_command.py,sha256=
|
101
|
+
mcp_proxy_adapter/tests/commands/test_help_command.py,sha256=0kylFDGSYV-YStVCf_j7_4EF8VDaClIZbJz3V2V2-DI,4272
|
99
102
|
mcp_proxy_adapter/tests/functional/__init__.py,sha256=muVNR6LD5o7DsDaLrbLTFsavUNcnyM608-mr-dqzgDU,59
|
100
103
|
mcp_proxy_adapter/tests/functional/test_api.py,sha256=OaGB-WAWVyX4b0b-mCdXBNhwwYABYeBPO3IDnA3I00c,7114
|
101
104
|
mcp_proxy_adapter/tests/integration/__init__.py,sha256=JZpeNG1PBRZ3k5zfq6NH3GyzDc1Yx1ZUgwi6eLBxs1o,60
|
102
|
-
mcp_proxy_adapter/tests/integration/test_cmd_integration.py,sha256=
|
105
|
+
mcp_proxy_adapter/tests/integration/test_cmd_integration.py,sha256=BS3lA6ayveMckHcy1WJjyqR7l7WTcjmGiCYSnMjVfO0,3415
|
103
106
|
mcp_proxy_adapter/tests/integration/test_integration.py,sha256=Rf8GTxdZOvZzrtgqWN2fp-36qUU5rpHdV9zhN1JxNw8,6619
|
104
107
|
mcp_proxy_adapter/tests/performance/__init__.py,sha256=2kHf6g4LmYnFuV4EALXzo7Qk9vHGA9DXZFt7nORRFjM,60
|
105
108
|
mcp_proxy_adapter/tests/performance/test_performance.py,sha256=Djrnu-SsXRrc_Prj1Aw8OoPzPUwHJds-Itk3aX6o01w,5730
|
@@ -108,8 +111,8 @@ mcp_proxy_adapter/tests/stubs/echo_command.py,sha256=Y7SA4IB5Lo_ncn78SDm9iRZvJSK
|
|
108
111
|
mcp_proxy_adapter/tests/unit/__init__.py,sha256=RS-5UoSCcLKtr2jrAaZw_NG9MquA6BZmxq-P6cTw9ok,53
|
109
112
|
mcp_proxy_adapter/tests/unit/test_base_command.py,sha256=ldDXQYk2eijbTgZioSBAhHzSAa_SuBKYqCutCEzUYTE,3924
|
110
113
|
mcp_proxy_adapter/tests/unit/test_config.py,sha256=SZ62LXFOv_fsV0fmSIBdHWvapEyexKrioFRQo0I4pkg,5900
|
111
|
-
mcp_proxy_adapter-3.1.
|
112
|
-
mcp_proxy_adapter-3.1.
|
113
|
-
mcp_proxy_adapter-3.1.
|
114
|
-
mcp_proxy_adapter-3.1.
|
115
|
-
mcp_proxy_adapter-3.1.
|
114
|
+
mcp_proxy_adapter-3.1.6.dist-info/licenses/LICENSE,sha256=OkApFEwdgMCt_mbvUI-eIwKMSTe38K3XnU2DT5ub-wI,1072
|
115
|
+
mcp_proxy_adapter-3.1.6.dist-info/METADATA,sha256=RbYESwlltxLaJLm8rVosrLljcIEkI1IT9VAVpWave9g,7537
|
116
|
+
mcp_proxy_adapter-3.1.6.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
|
117
|
+
mcp_proxy_adapter-3.1.6.dist-info/top_level.txt,sha256=kxq3OC7vBtsFdy9dDVse4cOl-SV_QlvcTeSkuw_jw3I,27
|
118
|
+
mcp_proxy_adapter-3.1.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|