mcp-proxy-adapter 2.1.17__py3-none-any.whl → 3.0.1__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/__init__.py +19 -0
- examples/anti_patterns/README.md +51 -0
- examples/anti_patterns/__init__.py +9 -0
- examples/anti_patterns/bad_design/README.md +72 -0
- examples/anti_patterns/bad_design/global_state.py +170 -0
- examples/anti_patterns/bad_design/monolithic_command.py +272 -0
- examples/basic_example/README.md +245 -0
- examples/basic_example/__init__.py +8 -0
- examples/basic_example/commands/__init__.py +5 -0
- examples/basic_example/commands/echo_command.py +95 -0
- examples/basic_example/commands/math_command.py +151 -0
- examples/basic_example/commands/time_command.py +152 -0
- examples/basic_example/config.json +25 -0
- examples/basic_example/docs/EN/README.md +177 -0
- examples/basic_example/docs/RU/README.md +177 -0
- examples/basic_example/server.py +151 -0
- examples/basic_example/tests/conftest.py +243 -0
- examples/commands/echo_command.py +52 -0
- examples/commands/echo_result.py +65 -0
- examples/commands/get_date_command.py +98 -0
- examples/commands/new_uuid4_command.py +91 -0
- examples/complete_example/Dockerfile +24 -0
- examples/complete_example/README.md +92 -0
- examples/complete_example/__init__.py +8 -0
- examples/complete_example/commands/__init__.py +5 -0
- examples/complete_example/commands/system_command.py +328 -0
- examples/complete_example/config.json +41 -0
- examples/complete_example/configs/config.dev.yaml +40 -0
- examples/complete_example/configs/config.docker.yaml +40 -0
- examples/complete_example/docker-compose.yml +35 -0
- examples/complete_example/requirements.txt +20 -0
- examples/complete_example/server.py +139 -0
- examples/minimal_example/README.md +65 -0
- examples/minimal_example/__init__.py +8 -0
- examples/minimal_example/config.json +14 -0
- examples/minimal_example/main.py +136 -0
- examples/minimal_example/simple_server.py +163 -0
- examples/minimal_example/tests/conftest.py +171 -0
- examples/minimal_example/tests/test_hello_command.py +111 -0
- examples/minimal_example/tests/test_integration.py +181 -0
- examples/server.py +69 -0
- examples/simple_server.py +128 -0
- examples/test_server.py +134 -0
- examples/tool_description_example.py +82 -0
- mcp_proxy_adapter/__init__.py +33 -1
- mcp_proxy_adapter/api/__init__.py +0 -0
- mcp_proxy_adapter/api/app.py +391 -0
- mcp_proxy_adapter/api/handlers.py +229 -0
- mcp_proxy_adapter/api/middleware/__init__.py +49 -0
- mcp_proxy_adapter/api/middleware/auth.py +146 -0
- mcp_proxy_adapter/api/middleware/base.py +79 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +198 -0
- mcp_proxy_adapter/api/middleware/logging.py +96 -0
- mcp_proxy_adapter/api/middleware/performance.py +83 -0
- mcp_proxy_adapter/api/middleware/rate_limit.py +152 -0
- mcp_proxy_adapter/api/schemas.py +305 -0
- mcp_proxy_adapter/api/tool_integration.py +223 -0
- mcp_proxy_adapter/api/tools.py +198 -0
- mcp_proxy_adapter/commands/__init__.py +19 -0
- mcp_proxy_adapter/commands/base.py +301 -0
- mcp_proxy_adapter/commands/command_registry.py +231 -0
- mcp_proxy_adapter/commands/config_command.py +113 -0
- mcp_proxy_adapter/commands/health_command.py +136 -0
- mcp_proxy_adapter/commands/help_command.py +193 -0
- mcp_proxy_adapter/commands/result.py +215 -0
- mcp_proxy_adapter/config.py +195 -0
- mcp_proxy_adapter/core/__init__.py +0 -0
- mcp_proxy_adapter/core/errors.py +173 -0
- mcp_proxy_adapter/core/logging.py +205 -0
- mcp_proxy_adapter/core/utils.py +138 -0
- mcp_proxy_adapter/custom_openapi.py +125 -0
- mcp_proxy_adapter/openapi.py +403 -0
- mcp_proxy_adapter/py.typed +0 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/tests/__init__.py +0 -0
- mcp_proxy_adapter/tests/api/__init__.py +3 -0
- mcp_proxy_adapter/tests/api/test_cmd_endpoint.py +115 -0
- mcp_proxy_adapter/tests/api/test_middleware.py +336 -0
- mcp_proxy_adapter/tests/commands/__init__.py +3 -0
- mcp_proxy_adapter/tests/commands/test_config_command.py +211 -0
- mcp_proxy_adapter/tests/commands/test_echo_command.py +127 -0
- mcp_proxy_adapter/tests/commands/test_help_command.py +133 -0
- mcp_proxy_adapter/tests/conftest.py +131 -0
- mcp_proxy_adapter/tests/functional/__init__.py +3 -0
- mcp_proxy_adapter/tests/functional/test_api.py +235 -0
- mcp_proxy_adapter/tests/integration/__init__.py +3 -0
- mcp_proxy_adapter/tests/integration/test_cmd_integration.py +130 -0
- mcp_proxy_adapter/tests/integration/test_integration.py +255 -0
- mcp_proxy_adapter/tests/performance/__init__.py +3 -0
- mcp_proxy_adapter/tests/performance/test_performance.py +189 -0
- mcp_proxy_adapter/tests/stubs/__init__.py +10 -0
- mcp_proxy_adapter/tests/stubs/echo_command.py +104 -0
- mcp_proxy_adapter/tests/test_api_endpoints.py +271 -0
- mcp_proxy_adapter/tests/test_api_handlers.py +289 -0
- mcp_proxy_adapter/tests/test_base_command.py +123 -0
- mcp_proxy_adapter/tests/test_batch_requests.py +117 -0
- mcp_proxy_adapter/tests/test_command_registry.py +245 -0
- mcp_proxy_adapter/tests/test_config.py +127 -0
- mcp_proxy_adapter/tests/test_utils.py +65 -0
- mcp_proxy_adapter/tests/unit/__init__.py +3 -0
- mcp_proxy_adapter/tests/unit/test_base_command.py +130 -0
- mcp_proxy_adapter/tests/unit/test_config.py +217 -0
- mcp_proxy_adapter/version.py +3 -0
- mcp_proxy_adapter-3.0.1.dist-info/METADATA +200 -0
- mcp_proxy_adapter-3.0.1.dist-info/RECORD +109 -0
- {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/top_level.txt +1 -0
- mcp_proxy_adapter/adapter.py +0 -697
- mcp_proxy_adapter/analyzers/__init__.py +0 -1
- mcp_proxy_adapter/analyzers/docstring_analyzer.py +0 -199
- mcp_proxy_adapter/analyzers/type_analyzer.py +0 -151
- mcp_proxy_adapter/dispatchers/__init__.py +0 -1
- mcp_proxy_adapter/dispatchers/base_dispatcher.py +0 -85
- mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +0 -262
- mcp_proxy_adapter/examples/analyze_config.py +0 -141
- mcp_proxy_adapter/examples/basic_integration.py +0 -155
- mcp_proxy_adapter/examples/docstring_and_schema_example.py +0 -69
- mcp_proxy_adapter/examples/extension_example.py +0 -72
- mcp_proxy_adapter/examples/help_best_practices.py +0 -67
- mcp_proxy_adapter/examples/help_usage.py +0 -64
- mcp_proxy_adapter/examples/mcp_proxy_client.py +0 -131
- mcp_proxy_adapter/examples/openapi_server.py +0 -383
- mcp_proxy_adapter/examples/project_structure_example.py +0 -47
- mcp_proxy_adapter/examples/testing_example.py +0 -64
- mcp_proxy_adapter/models.py +0 -47
- mcp_proxy_adapter/registry.py +0 -439
- mcp_proxy_adapter/schema.py +0 -257
- mcp_proxy_adapter/testing_utils.py +0 -112
- mcp_proxy_adapter/validators/__init__.py +0 -1
- mcp_proxy_adapter/validators/docstring_validator.py +0 -75
- mcp_proxy_adapter/validators/metadata_validator.py +0 -76
- mcp_proxy_adapter-2.1.17.dist-info/METADATA +0 -376
- mcp_proxy_adapter-2.1.17.dist-info/RECORD +0 -30
- {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-2.1.17.dist-info → mcp_proxy_adapter-3.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
"""
|
2
|
+
Integration tests for the minimal example of MCP Proxy Adapter.
|
3
|
+
|
4
|
+
These tests start a real server instance and test the API endpoints.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import time
|
9
|
+
import pytest
|
10
|
+
import requests
|
11
|
+
from typing import Dict, Any, Callable
|
12
|
+
|
13
|
+
from conftest import ServerProcess
|
14
|
+
|
15
|
+
|
16
|
+
class TestHelloCommandIntegration:
|
17
|
+
"""Integration tests for the HelloCommand API."""
|
18
|
+
|
19
|
+
def test_jsonrpc_hello_default(self, server: ServerProcess, jsonrpc_client: Callable):
|
20
|
+
"""Test the hello command via JSON-RPC with default parameters."""
|
21
|
+
# Make JSON-RPC request
|
22
|
+
response = jsonrpc_client("hello", {})
|
23
|
+
|
24
|
+
# Check response
|
25
|
+
assert "jsonrpc" in response
|
26
|
+
assert response["jsonrpc"] == "2.0"
|
27
|
+
assert "id" in response
|
28
|
+
assert "result" in response
|
29
|
+
assert "message" in response["result"]
|
30
|
+
assert response["result"]["message"] == "Hello, World!"
|
31
|
+
|
32
|
+
def test_jsonrpc_hello_custom_name(self, server: ServerProcess, jsonrpc_client: Callable):
|
33
|
+
"""Test the hello command via JSON-RPC with custom name parameter."""
|
34
|
+
# Make JSON-RPC request
|
35
|
+
response = jsonrpc_client("hello", {"name": "Integration Test"})
|
36
|
+
|
37
|
+
# Check response
|
38
|
+
assert "result" in response
|
39
|
+
assert "message" in response["result"]
|
40
|
+
assert response["result"]["message"] == "Hello, Integration Test!"
|
41
|
+
|
42
|
+
def test_cmd_endpoint_hello(self, server: ServerProcess, api_url: str):
|
43
|
+
"""Test the hello command via the /cmd endpoint."""
|
44
|
+
# Prepare request
|
45
|
+
payload = {
|
46
|
+
"command": "hello",
|
47
|
+
"params": {"name": "CMD Endpoint"}
|
48
|
+
}
|
49
|
+
|
50
|
+
# Make request
|
51
|
+
response = requests.post(
|
52
|
+
f"{api_url}/cmd",
|
53
|
+
json=payload,
|
54
|
+
headers={"Content-Type": "application/json"}
|
55
|
+
)
|
56
|
+
|
57
|
+
# Check response
|
58
|
+
assert response.status_code == 200
|
59
|
+
data = response.json()
|
60
|
+
assert "result" in data
|
61
|
+
assert "message" in data["result"]
|
62
|
+
assert data["result"]["message"] == "Hello, CMD Endpoint!"
|
63
|
+
|
64
|
+
def test_api_command_endpoint_hello(self, server: ServerProcess, api_url: str):
|
65
|
+
"""Test the hello command via the /api/command/{command_name} endpoint."""
|
66
|
+
# Prepare params
|
67
|
+
params = {"name": "API Command Endpoint"}
|
68
|
+
|
69
|
+
# Make request
|
70
|
+
response = requests.post(
|
71
|
+
f"{api_url}/api/command/hello",
|
72
|
+
json=params,
|
73
|
+
headers={"Content-Type": "application/json"}
|
74
|
+
)
|
75
|
+
|
76
|
+
# Check response
|
77
|
+
assert response.status_code == 200
|
78
|
+
data = response.json()
|
79
|
+
assert "message" in data
|
80
|
+
assert data["message"] == "Hello, API Command Endpoint!"
|
81
|
+
|
82
|
+
def test_jsonrpc_batch_request(self, server: ServerProcess, api_url: str):
|
83
|
+
"""Test batch JSON-RPC requests with hello command."""
|
84
|
+
# Prepare batch request
|
85
|
+
batch = [
|
86
|
+
{
|
87
|
+
"jsonrpc": "2.0",
|
88
|
+
"method": "hello",
|
89
|
+
"params": {"name": "Batch 1"},
|
90
|
+
"id": 1
|
91
|
+
},
|
92
|
+
{
|
93
|
+
"jsonrpc": "2.0",
|
94
|
+
"method": "hello",
|
95
|
+
"params": {"name": "Batch 2"},
|
96
|
+
"id": 2
|
97
|
+
}
|
98
|
+
]
|
99
|
+
|
100
|
+
# Make request
|
101
|
+
response = requests.post(
|
102
|
+
f"{api_url}/api/jsonrpc",
|
103
|
+
json=batch,
|
104
|
+
headers={"Content-Type": "application/json"}
|
105
|
+
)
|
106
|
+
|
107
|
+
# Check response
|
108
|
+
assert response.status_code == 200
|
109
|
+
data = response.json()
|
110
|
+
assert isinstance(data, list)
|
111
|
+
assert len(data) == 2
|
112
|
+
|
113
|
+
# Check first result
|
114
|
+
assert data[0]["id"] == 1
|
115
|
+
assert data[0]["result"]["message"] == "Hello, Batch 1!"
|
116
|
+
|
117
|
+
# Check second result
|
118
|
+
assert data[1]["id"] == 2
|
119
|
+
assert data[1]["result"]["message"] == "Hello, Batch 2!"
|
120
|
+
|
121
|
+
|
122
|
+
class TestServerIntegration:
|
123
|
+
"""Integration tests for the server itself."""
|
124
|
+
|
125
|
+
def test_health_endpoint(self, server: ServerProcess, api_url: str):
|
126
|
+
"""Test the /health endpoint."""
|
127
|
+
response = requests.get(f"{api_url}/health")
|
128
|
+
|
129
|
+
# Check response
|
130
|
+
assert response.status_code == 200
|
131
|
+
data = response.json()
|
132
|
+
assert "status" in data
|
133
|
+
assert data["status"] == "ok"
|
134
|
+
|
135
|
+
def test_openapi_schema(self, server: ServerProcess, api_url: str):
|
136
|
+
"""Test the OpenAPI schema endpoint."""
|
137
|
+
response = requests.get(f"{api_url}/openapi.json")
|
138
|
+
|
139
|
+
# Check response
|
140
|
+
assert response.status_code == 200
|
141
|
+
schema = response.json()
|
142
|
+
|
143
|
+
# Check schema structure
|
144
|
+
assert "openapi" in schema
|
145
|
+
assert "info" in schema
|
146
|
+
assert "paths" in schema
|
147
|
+
|
148
|
+
# Проверяем наличие основных эндпоинтов
|
149
|
+
assert "/api/jsonrpc" in schema["paths"] or "/cmd" in schema["paths"]
|
150
|
+
assert "/api/commands" in schema["paths"]
|
151
|
+
|
152
|
+
def test_docs_endpoint(self, server: ServerProcess, api_url: str):
|
153
|
+
"""Test the Swagger UI endpoint."""
|
154
|
+
response = requests.get(f"{api_url}/docs")
|
155
|
+
|
156
|
+
# Check response
|
157
|
+
assert response.status_code == 200
|
158
|
+
assert "text/html" in response.headers["Content-Type"]
|
159
|
+
|
160
|
+
# Check if swagger UI is in the response
|
161
|
+
assert "swagger-ui" in response.text.lower()
|
162
|
+
|
163
|
+
def test_commands_list_endpoint(self, server: ServerProcess, api_url: str):
|
164
|
+
"""Test the commands list endpoint."""
|
165
|
+
response = requests.get(f"{api_url}/api/commands")
|
166
|
+
|
167
|
+
# Check response
|
168
|
+
assert response.status_code == 200
|
169
|
+
data = response.json()
|
170
|
+
|
171
|
+
# Check data structure
|
172
|
+
assert "commands" in data
|
173
|
+
assert isinstance(data["commands"], dict) # Теперь commands это словарь, а не список
|
174
|
+
|
175
|
+
# Check if hello command is in the list
|
176
|
+
assert "hello" in data["commands"]
|
177
|
+
|
178
|
+
# Check hello command details
|
179
|
+
hello_cmd = data["commands"]["hello"]
|
180
|
+
assert "name" in hello_cmd
|
181
|
+
assert hello_cmd["name"] == "hello"
|
examples/server.py
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
"""
|
2
|
+
Main application module.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import os
|
6
|
+
import sys
|
7
|
+
import uvicorn
|
8
|
+
import logging
|
9
|
+
|
10
|
+
from mcp_proxy_adapter import create_app
|
11
|
+
|
12
|
+
app = create_app()
|
13
|
+
from mcp_proxy_adapter.config import config
|
14
|
+
from mcp_proxy_adapter.core.logging import logger, setup_logging
|
15
|
+
|
16
|
+
|
17
|
+
def main():
|
18
|
+
"""
|
19
|
+
Main function to run the application.
|
20
|
+
"""
|
21
|
+
# Убедимся что логирование настроено
|
22
|
+
logger.info("Initializing logging configuration")
|
23
|
+
|
24
|
+
try:
|
25
|
+
# Получаем настройки логирования
|
26
|
+
log_level = config.get("logging.level", "INFO")
|
27
|
+
log_file = config.get("logging.file")
|
28
|
+
rotation_type = config.get("logging.rotation.type", "size")
|
29
|
+
|
30
|
+
# Выводим информацию о настройках логирования
|
31
|
+
logger.info(f"Log level: {log_level}")
|
32
|
+
if log_file:
|
33
|
+
logger.info(f"Log file: {log_file}")
|
34
|
+
logger.info(f"Log rotation type: {rotation_type}")
|
35
|
+
|
36
|
+
if rotation_type.lower() == "time":
|
37
|
+
when = config.get("logging.rotation.when", "D")
|
38
|
+
interval = config.get("logging.rotation.interval", 1)
|
39
|
+
logger.info(f"Log rotation: every {interval} {when}")
|
40
|
+
else:
|
41
|
+
max_bytes = config.get("logging.rotation.max_bytes", 10 * 1024 * 1024)
|
42
|
+
logger.info(f"Log rotation: when size reaches {max_bytes / (1024*1024):.1f} MB")
|
43
|
+
|
44
|
+
backup_count = config.get("logging.rotation.backup_count", 5)
|
45
|
+
logger.info(f"Log backups: {backup_count}")
|
46
|
+
else:
|
47
|
+
logger.info("File logging is disabled")
|
48
|
+
|
49
|
+
# Get server settings
|
50
|
+
host = config.get("server.host", "0.0.0.0")
|
51
|
+
port = config.get("server.port", 8000)
|
52
|
+
|
53
|
+
logger.info(f"Starting server on {host}:{port}")
|
54
|
+
|
55
|
+
# Run server
|
56
|
+
uvicorn.run(
|
57
|
+
"mcp_proxy_adapter.api.app:app",
|
58
|
+
host=host,
|
59
|
+
port=port,
|
60
|
+
reload=True if os.environ.get("DEBUG") else False,
|
61
|
+
log_level=log_level.lower()
|
62
|
+
)
|
63
|
+
except Exception as e:
|
64
|
+
logger.exception(f"Error during application startup: {e}")
|
65
|
+
sys.exit(1)
|
66
|
+
|
67
|
+
|
68
|
+
if __name__ == "__main__":
|
69
|
+
main()
|
@@ -0,0 +1,128 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Простой пример запуска сервера JSON-RPC с использованием MCP Proxy Adapter.
|
4
|
+
|
5
|
+
Этот скрипт демонстрирует минимальную конфигурацию для запуска сервера JSON-RPC.
|
6
|
+
Он создаёт экземпляр приложения FastAPI с MCP Proxy Adapter и регистрирует пользовательские команды.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import os
|
10
|
+
import argparse
|
11
|
+
import sys
|
12
|
+
from pathlib import Path
|
13
|
+
import uvicorn
|
14
|
+
|
15
|
+
# Добавляем родительскую директорию в PYTHONPATH для импорта mcp_proxy_adapter
|
16
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
17
|
+
|
18
|
+
from mcp_proxy_adapter import Command, SuccessResult, create_app
|
19
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
20
|
+
from typing import Dict, Any, Optional
|
21
|
+
|
22
|
+
|
23
|
+
class HelloResult(SuccessResult):
|
24
|
+
"""Result of hello command."""
|
25
|
+
|
26
|
+
def __init__(self, message: str):
|
27
|
+
"""
|
28
|
+
Initialize result.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
message: Hello message
|
32
|
+
"""
|
33
|
+
self.message = message
|
34
|
+
|
35
|
+
def to_dict(self) -> Dict[str, Any]:
|
36
|
+
"""
|
37
|
+
Convert result to dictionary.
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
Dictionary representation
|
41
|
+
"""
|
42
|
+
return {"message": self.message}
|
43
|
+
|
44
|
+
@classmethod
|
45
|
+
def get_schema(cls) -> Dict[str, Any]:
|
46
|
+
"""
|
47
|
+
Get JSON schema for result.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
JSON schema
|
51
|
+
"""
|
52
|
+
return {
|
53
|
+
"type": "object",
|
54
|
+
"properties": {
|
55
|
+
"message": {"type": "string"}
|
56
|
+
},
|
57
|
+
"required": ["message"]
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
class HelloCommand(Command):
|
62
|
+
"""Command that returns hello message."""
|
63
|
+
|
64
|
+
name = "hello"
|
65
|
+
result_class = HelloResult
|
66
|
+
|
67
|
+
async def execute(self, name: str = "World") -> HelloResult:
|
68
|
+
"""
|
69
|
+
Execute command.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
name: Name to greet
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
Hello result
|
76
|
+
"""
|
77
|
+
return HelloResult(f"Hello, {name}!")
|
78
|
+
|
79
|
+
@classmethod
|
80
|
+
def get_schema(cls) -> Dict[str, Any]:
|
81
|
+
"""
|
82
|
+
Get JSON schema for command parameters.
|
83
|
+
|
84
|
+
Returns:
|
85
|
+
JSON schema
|
86
|
+
"""
|
87
|
+
return {
|
88
|
+
"type": "object",
|
89
|
+
"properties": {
|
90
|
+
"name": {"type": "string"}
|
91
|
+
},
|
92
|
+
"additionalProperties": False
|
93
|
+
}
|
94
|
+
|
95
|
+
|
96
|
+
def main():
|
97
|
+
"""
|
98
|
+
Основная функция для запуска сервера.
|
99
|
+
"""
|
100
|
+
parser = argparse.ArgumentParser(description="JSON-RPC Microservice Server")
|
101
|
+
parser.add_argument("--host", default="0.0.0.0", help="Host to bind server")
|
102
|
+
parser.add_argument("--port", type=int, default=8000, help="Port to bind server")
|
103
|
+
parser.add_argument("--reload", action="store_true", help="Enable auto-reload")
|
104
|
+
|
105
|
+
args = parser.parse_args()
|
106
|
+
|
107
|
+
# Регистрируем только свою пользовательскую команду
|
108
|
+
# встроенные команды и примеры регистрируются автоматически
|
109
|
+
registry.register(HelloCommand)
|
110
|
+
|
111
|
+
# Создаем приложение FastAPI
|
112
|
+
app = create_app()
|
113
|
+
|
114
|
+
# Запускаем сервер
|
115
|
+
uvicorn.run(
|
116
|
+
app,
|
117
|
+
host=args.host,
|
118
|
+
port=args.port,
|
119
|
+
reload=args.reload
|
120
|
+
)
|
121
|
+
|
122
|
+
|
123
|
+
if __name__ == "__main__":
|
124
|
+
# Run the simple server example
|
125
|
+
# To test, open http://localhost:8000/docs in your browser
|
126
|
+
# or use curl:
|
127
|
+
# curl -X POST http://localhost:8000/api/cmd -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"hello","params":{"name":"PyPI"},"id":1}'
|
128
|
+
main()
|
examples/test_server.py
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Тестовый скрипт для запуска сервера JSON-RPC с использованием MCP Proxy Adapter.
|
4
|
+
Использует только базовую команду для тестирования установки пакета.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import os
|
8
|
+
import argparse
|
9
|
+
import sys
|
10
|
+
import uvicorn
|
11
|
+
from pathlib import Path
|
12
|
+
from typing import Dict, Any, Optional
|
13
|
+
|
14
|
+
# Добавляем родительскую директорию в PYTHONPATH для импорта mcp_proxy_adapter
|
15
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
16
|
+
|
17
|
+
from mcp_proxy_adapter import Command, SuccessResult, create_app, registry
|
18
|
+
from mcp_proxy_adapter.core.logging import setup_logging
|
19
|
+
from mcp_proxy_adapter.config import config
|
20
|
+
|
21
|
+
|
22
|
+
class HelloResult(SuccessResult):
|
23
|
+
"""Result of hello command."""
|
24
|
+
|
25
|
+
def __init__(self, message: str):
|
26
|
+
"""
|
27
|
+
Initialize result.
|
28
|
+
|
29
|
+
Args:
|
30
|
+
message: Hello message
|
31
|
+
"""
|
32
|
+
self.message = message
|
33
|
+
|
34
|
+
def to_dict(self) -> Dict[str, Any]:
|
35
|
+
"""
|
36
|
+
Convert result to dictionary.
|
37
|
+
|
38
|
+
Returns:
|
39
|
+
Dictionary representation
|
40
|
+
"""
|
41
|
+
return {"message": self.message}
|
42
|
+
|
43
|
+
@classmethod
|
44
|
+
def get_schema(cls) -> Dict[str, Any]:
|
45
|
+
"""
|
46
|
+
Get JSON schema for result.
|
47
|
+
|
48
|
+
Returns:
|
49
|
+
JSON schema
|
50
|
+
"""
|
51
|
+
return {
|
52
|
+
"type": "object",
|
53
|
+
"properties": {
|
54
|
+
"message": {"type": "string"}
|
55
|
+
},
|
56
|
+
"required": ["message"]
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
class HelloCommand(Command):
|
61
|
+
"""Command that returns hello message."""
|
62
|
+
|
63
|
+
name = "hello"
|
64
|
+
result_class = HelloResult
|
65
|
+
|
66
|
+
async def execute(self, name: str = "World") -> HelloResult:
|
67
|
+
"""
|
68
|
+
Execute command.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
name: Name to greet
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
Hello result
|
75
|
+
"""
|
76
|
+
return HelloResult(f"Hello, {name}!")
|
77
|
+
|
78
|
+
@classmethod
|
79
|
+
def get_schema(cls) -> Dict[str, Any]:
|
80
|
+
"""
|
81
|
+
Get JSON schema for command parameters.
|
82
|
+
|
83
|
+
Returns:
|
84
|
+
JSON schema
|
85
|
+
"""
|
86
|
+
return {
|
87
|
+
"type": "object",
|
88
|
+
"properties": {
|
89
|
+
"name": {"type": "string"}
|
90
|
+
},
|
91
|
+
"additionalProperties": False
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
def main():
|
96
|
+
"""
|
97
|
+
Основная функция для запуска сервера.
|
98
|
+
"""
|
99
|
+
parser = argparse.ArgumentParser(description="Test JSON-RPC Microservice Server")
|
100
|
+
parser.add_argument("--host", default="0.0.0.0", help="Host to bind server")
|
101
|
+
parser.add_argument("--port", type=int, default=8000, help="Port to bind server")
|
102
|
+
parser.add_argument("--reload", action="store_true", help="Enable auto-reload")
|
103
|
+
parser.add_argument("--config", help="Path to config file")
|
104
|
+
|
105
|
+
args = parser.parse_args()
|
106
|
+
|
107
|
+
# Инициализируем конфигурацию
|
108
|
+
if args.config and os.path.exists(args.config):
|
109
|
+
config.load_from_file(args.config)
|
110
|
+
|
111
|
+
# Настраиваем логирование
|
112
|
+
setup_logging("INFO")
|
113
|
+
|
114
|
+
# Создаем приложение FastAPI
|
115
|
+
app = create_app()
|
116
|
+
app.title = "Test Microservice"
|
117
|
+
app.description = "Test microservice for package installation verification"
|
118
|
+
app.version = "1.0.0"
|
119
|
+
|
120
|
+
# Регистрируем только одну команду для тестирования
|
121
|
+
registry.register(HelloCommand)
|
122
|
+
|
123
|
+
# Запускаем сервер
|
124
|
+
uvicorn.run(
|
125
|
+
app,
|
126
|
+
host=args.host,
|
127
|
+
port=args.port,
|
128
|
+
reload=args.reload,
|
129
|
+
log_level="info"
|
130
|
+
)
|
131
|
+
|
132
|
+
|
133
|
+
if __name__ == "__main__":
|
134
|
+
main()
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
"""
|
3
|
+
Example of using the API tool description functionality.
|
4
|
+
|
5
|
+
This script demonstrates how to use the API tool description functionality
|
6
|
+
to generate rich and informative descriptions for API tools.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import json
|
10
|
+
import asyncio
|
11
|
+
import sys
|
12
|
+
from pathlib import Path
|
13
|
+
|
14
|
+
# Add the project root to the Python path
|
15
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
16
|
+
|
17
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
18
|
+
from mcp_proxy_adapter.api.schemas import APIToolDescription
|
19
|
+
from mcp_proxy_adapter.api.tools import get_tool_description, TSTCommandExecutor
|
20
|
+
from mcp_proxy_adapter.commands.help_command import HelpCommand
|
21
|
+
|
22
|
+
|
23
|
+
async def main():
|
24
|
+
"""Main function to demonstrate API tool description functionality."""
|
25
|
+
|
26
|
+
# Register the help command so we have at least one command registered
|
27
|
+
if not registry.command_exists("help"):
|
28
|
+
registry.register(HelpCommand)
|
29
|
+
|
30
|
+
# Generate description using the APIToolDescription class directly
|
31
|
+
print("Generating tool description using APIToolDescription:")
|
32
|
+
description = APIToolDescription.generate_tool_description("tst_execute_command", registry)
|
33
|
+
print(json.dumps(description, indent=2, ensure_ascii=False))
|
34
|
+
print("\n" + "-" * 80 + "\n")
|
35
|
+
|
36
|
+
# Generate text description using the APIToolDescription class
|
37
|
+
print("Generating tool description text using APIToolDescription:")
|
38
|
+
description_text = APIToolDescription.generate_tool_description_text("tst_execute_command", registry)
|
39
|
+
print(description_text)
|
40
|
+
print("\n" + "-" * 80 + "\n")
|
41
|
+
|
42
|
+
# Get tool description using the tools module
|
43
|
+
print("Getting tool description using the tools module:")
|
44
|
+
tool_description = get_tool_description("tst_execute_command")
|
45
|
+
print(json.dumps(tool_description, indent=2, ensure_ascii=False))
|
46
|
+
print("\n" + "-" * 80 + "\n")
|
47
|
+
|
48
|
+
# Get tool description in markdown format using the tools module
|
49
|
+
print("Getting tool description in markdown format using the tools module:")
|
50
|
+
tool_description_md = get_tool_description("tst_execute_command", "markdown")
|
51
|
+
print(tool_description_md)
|
52
|
+
print("\n" + "-" * 80 + "\n")
|
53
|
+
|
54
|
+
# Get tool schema directly from the tool class
|
55
|
+
print("Getting tool schema directly from the tool class:")
|
56
|
+
tool_schema = TSTCommandExecutor.get_schema()
|
57
|
+
print(json.dumps(tool_schema, indent=2, ensure_ascii=False))
|
58
|
+
print("\n" + "-" * 80 + "\n")
|
59
|
+
|
60
|
+
# Get tool description directly from the tool class
|
61
|
+
print("Getting tool description directly from the tool class:")
|
62
|
+
tool_desc = TSTCommandExecutor.get_description("json")
|
63
|
+
print(json.dumps(tool_desc, indent=2, ensure_ascii=False))
|
64
|
+
print("\n" + "-" * 80 + "\n")
|
65
|
+
|
66
|
+
# Show how this can be used to create informative command-line help
|
67
|
+
print("Example command-line help based on tool description:")
|
68
|
+
help_text = f"""
|
69
|
+
{TSTCommandExecutor.name} - {TSTCommandExecutor.description}
|
70
|
+
|
71
|
+
Available commands:
|
72
|
+
"""
|
73
|
+
|
74
|
+
for cmd_name in tool_schema["parameters"]["properties"]["command"]["enum"]:
|
75
|
+
cmd_info = description["supported_commands"].get(cmd_name, {})
|
76
|
+
help_text += f" {cmd_name} - {cmd_info.get('summary', '')}\n"
|
77
|
+
|
78
|
+
print(help_text)
|
79
|
+
|
80
|
+
|
81
|
+
if __name__ == "__main__":
|
82
|
+
asyncio.run(main())
|
mcp_proxy_adapter/__init__.py
CHANGED
@@ -1 +1,33 @@
|
|
1
|
-
|
1
|
+
"""MCP Proxy API Service package.
|
2
|
+
|
3
|
+
This package provides a framework for creating JSON-RPC-enabled microservices.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from mcp_proxy_adapter.version import __version__
|
7
|
+
from mcp_proxy_adapter.api.app import create_app
|
8
|
+
from mcp_proxy_adapter.commands.base import Command
|
9
|
+
from mcp_proxy_adapter.commands.result import CommandResult, SuccessResult, ErrorResult
|
10
|
+
from mcp_proxy_adapter.commands.command_registry import registry
|
11
|
+
from mcp_proxy_adapter.core.errors import (
|
12
|
+
MicroserviceError, CommandError, ValidationError,
|
13
|
+
InvalidParamsError, NotFoundError, TimeoutError,
|
14
|
+
InternalError
|
15
|
+
)
|
16
|
+
|
17
|
+
# Экспортируем основные классы и функции для удобного использования
|
18
|
+
__all__ = [
|
19
|
+
"__version__",
|
20
|
+
"create_app",
|
21
|
+
"Command",
|
22
|
+
"CommandResult",
|
23
|
+
"SuccessResult",
|
24
|
+
"ErrorResult",
|
25
|
+
"registry",
|
26
|
+
"MicroserviceError",
|
27
|
+
"CommandError",
|
28
|
+
"ValidationError",
|
29
|
+
"InvalidParamsError",
|
30
|
+
"NotFoundError",
|
31
|
+
"TimeoutError",
|
32
|
+
"InternalError"
|
33
|
+
]
|
File without changes
|