mcp-proxy-adapter 3.0.1__py3-none-any.whl → 3.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/complete_example/server.py +33 -59
- mcp_proxy_adapter/api/tool_integration.py +2 -1
- mcp_proxy_adapter/custom_openapi.py +47 -10
- mcp_proxy_adapter/tests/functional/test_api.py +19 -1
- mcp_proxy_adapter/version.py +1 -1
- {mcp_proxy_adapter-3.0.1.dist-info → mcp_proxy_adapter-3.0.3.dist-info}/METADATA +2 -2
- {mcp_proxy_adapter-3.0.1.dist-info → mcp_proxy_adapter-3.0.3.dist-info}/RECORD +10 -10
- {mcp_proxy_adapter-3.0.1.dist-info → mcp_proxy_adapter-3.0.3.dist-info}/WHEEL +1 -1
- {mcp_proxy_adapter-3.0.1.dist-info → mcp_proxy_adapter-3.0.3.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-3.0.1.dist-info → mcp_proxy_adapter-3.0.3.dist-info}/top_level.txt +0 -0
@@ -8,14 +8,12 @@ environment-specific configuration, and multiple commands.
|
|
8
8
|
import os
|
9
9
|
import sys
|
10
10
|
import argparse
|
11
|
-
from typing import Dict, Any
|
12
11
|
from pathlib import Path
|
13
|
-
|
14
|
-
|
15
|
-
from mcp_proxy_adapter import MicroService
|
12
|
+
import uvicorn
|
13
|
+
from mcp_proxy_adapter.api.app import create_app
|
16
14
|
from mcp_proxy_adapter.commands.command_registry import registry
|
17
|
-
from mcp_proxy_adapter.core.logging import logger
|
18
15
|
from mcp_proxy_adapter.config import config
|
16
|
+
from mcp_proxy_adapter.core.logging import logger, setup_logging
|
19
17
|
|
20
18
|
# Add commands directory to path for local imports
|
21
19
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
@@ -28,32 +26,22 @@ def parse_args():
|
|
28
26
|
Returns:
|
29
27
|
Parsed arguments
|
30
28
|
"""
|
31
|
-
parser = argparse.ArgumentParser(description="MCP
|
29
|
+
parser = argparse.ArgumentParser(description="MCP Complete Example")
|
32
30
|
parser.add_argument(
|
33
|
-
"--config",
|
31
|
+
"--config",
|
34
32
|
default="configs/config.dev.yaml",
|
35
33
|
help="Path to configuration file"
|
36
34
|
)
|
37
35
|
return parser.parse_args()
|
38
36
|
|
39
37
|
|
40
|
-
def ensure_directories(
|
38
|
+
def ensure_directories():
|
41
39
|
"""
|
42
40
|
Create necessary directories based on configuration.
|
43
|
-
|
44
|
-
Args:
|
45
|
-
config_path: Path to configuration file
|
46
41
|
"""
|
47
|
-
# Extract base directory
|
48
42
|
base_dir = os.path.dirname(os.path.abspath(__file__))
|
49
|
-
|
50
|
-
# Create logs directory
|
51
43
|
os.makedirs(os.path.join(base_dir, "logs"), exist_ok=True)
|
52
|
-
|
53
|
-
# Create cache directory
|
54
44
|
os.makedirs(os.path.join(base_dir, "cache"), exist_ok=True)
|
55
|
-
|
56
|
-
# Create data directory
|
57
45
|
os.makedirs(os.path.join(base_dir, "data"), exist_ok=True)
|
58
46
|
|
59
47
|
|
@@ -65,74 +53,60 @@ def setup_application(config_file=None):
|
|
65
53
|
config_file: Path to configuration file (optional)
|
66
54
|
|
67
55
|
Returns:
|
68
|
-
Configured
|
56
|
+
Configured FastAPI application
|
69
57
|
"""
|
70
|
-
# Parse command line arguments if config_file not provided
|
71
58
|
if config_file is None:
|
72
59
|
args = parse_args()
|
73
60
|
config_file = args.config
|
74
|
-
|
75
|
-
# Get absolute path to config file
|
76
61
|
current_dir = Path(__file__).parent.absolute()
|
77
62
|
config_path = current_dir / config_file
|
78
|
-
|
79
|
-
# Fall back to config.json if specified file doesn't exist
|
80
63
|
if not config_path.exists():
|
81
64
|
config_path = current_dir / "config.json"
|
82
|
-
|
83
|
-
# Create necessary directories
|
84
|
-
ensure_directories(str(config_path))
|
85
|
-
|
86
|
-
# Load configuration if exists
|
65
|
+
ensure_directories()
|
87
66
|
if config_path.exists():
|
88
67
|
config.load_from_file(str(config_path))
|
89
68
|
logger.info(f"Loaded configuration from {config_path}")
|
90
69
|
else:
|
91
70
|
logger.warning(f"Configuration file {config_path} not found, using defaults")
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
config_path=str(config_path) if config_path.exists() else None
|
99
|
-
)
|
100
|
-
|
101
|
-
# Safely register commands from package
|
71
|
+
app = create_app()
|
72
|
+
app.title = "Complete MCP Microservice Example"
|
73
|
+
app.description = "Full-featured microservice with Docker support"
|
74
|
+
app.version = "1.0.0"
|
75
|
+
# Discover and register commands from the commands directory
|
76
|
+
package_path = "commands"
|
102
77
|
try:
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
# Get currently registered commands
|
107
|
-
commands = registry.get_all_commands()
|
108
|
-
for cmd_name in list(commands.keys()):
|
78
|
+
registered_commands = registry.get_all_commands()
|
79
|
+
for cmd_name in list(registered_commands.keys()):
|
109
80
|
try:
|
110
81
|
registry.unregister(cmd_name)
|
111
82
|
except Exception as e:
|
112
83
|
logger.debug(f"Error unregistering command {cmd_name}: {e}")
|
113
|
-
|
114
|
-
|
115
|
-
service.discover_commands(package_path)
|
116
|
-
logger.info(f"Discovered and registered commands from package: {package_path}")
|
84
|
+
registry.discover_commands(package_path)
|
85
|
+
logger.info(f"Discovered commands from package: {package_path}")
|
117
86
|
except Exception as e:
|
118
87
|
logger.error(f"Error discovering commands: {e}")
|
119
|
-
|
120
|
-
return service
|
88
|
+
return app
|
121
89
|
|
122
90
|
|
123
91
|
def main():
|
124
92
|
"""Run microservice with command discovery."""
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
93
|
+
log_level = config.get("logging.level", "INFO")
|
94
|
+
setup_logging(log_level)
|
95
|
+
app = setup_application()
|
96
|
+
host = config.get("server.host", "0.0.0.0")
|
97
|
+
port = config.get("server.port", 8000)
|
129
98
|
if "TEST_SERVER_PORT" in os.environ:
|
130
99
|
port = int(os.environ["TEST_SERVER_PORT"])
|
131
|
-
service.port = port
|
132
100
|
logger.info(f"Using test port from environment: {port}")
|
133
|
-
|
134
|
-
|
135
|
-
|
101
|
+
logger.info(f"Starting server on {host}:{port}")
|
102
|
+
debug = config.get("server.debug", False)
|
103
|
+
uvicorn.run(
|
104
|
+
app,
|
105
|
+
host=host,
|
106
|
+
port=port,
|
107
|
+
reload=debug,
|
108
|
+
log_level=log_level.lower()
|
109
|
+
)
|
136
110
|
|
137
111
|
|
138
112
|
if __name__ == "__main__":
|
@@ -90,7 +90,8 @@ class ToolIntegration:
|
|
90
90
|
# использоваться библиотека для конвертации markdown в HTML)
|
91
91
|
markdown = APIToolDescription.generate_tool_description_text(tool_name, registry)
|
92
92
|
# Простая конвертация для примера
|
93
|
-
|
93
|
+
body = markdown.replace('#', '<h1>').replace('\n\n', '</p><p>')
|
94
|
+
html = f"<html><body>{body}</body></html>"
|
94
95
|
return html
|
95
96
|
else:
|
96
97
|
# По умолчанию возвращаем markdown
|
@@ -18,8 +18,16 @@ class CustomOpenAPIGenerator:
|
|
18
18
|
"""
|
19
19
|
Custom OpenAPI schema generator for compatibility with MCP-Proxy.
|
20
20
|
|
21
|
+
EN:
|
21
22
|
This generator creates an OpenAPI schema that matches the format expected by MCP-Proxy,
|
22
23
|
enabling dynamic command loading and proper tool representation in AI models.
|
24
|
+
Allows overriding title, description, and version for schema customization.
|
25
|
+
|
26
|
+
RU:
|
27
|
+
Кастомный генератор схемы OpenAPI для совместимости с MCP-Proxy.
|
28
|
+
Позволяет создавать схему OpenAPI в формате, ожидаемом MCP-Proxy,
|
29
|
+
с возможностью динамической подгрузки команд и корректного отображения инструментов для AI-моделей.
|
30
|
+
Поддерживает переопределение title, description и version для кастомизации схемы.
|
23
31
|
"""
|
24
32
|
|
25
33
|
def __init__(self):
|
@@ -88,38 +96,67 @@ class CustomOpenAPIGenerator:
|
|
88
96
|
|
89
97
|
return cmd_schema
|
90
98
|
|
91
|
-
def generate(self) -> Dict[str, Any]:
|
99
|
+
def generate(self, title: Optional[str] = None, description: Optional[str] = None, version: Optional[str] = None) -> Dict[str, Any]:
|
92
100
|
"""
|
101
|
+
EN:
|
93
102
|
Generate the complete OpenAPI schema compatible with MCP-Proxy.
|
103
|
+
Optionally override title, description, and version.
|
104
|
+
|
105
|
+
RU:
|
106
|
+
Генерирует полную схему OpenAPI, совместимую с MCP-Proxy.
|
107
|
+
Позволяет опционально переопределить title, description и version.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
title: Custom title for the schema / Кастомный заголовок схемы
|
111
|
+
description: Custom description for the schema / Кастомное описание схемы
|
112
|
+
version: Custom version for the schema / Кастомная версия схемы
|
94
113
|
|
95
114
|
Returns:
|
96
|
-
Dict containing the complete OpenAPI schema
|
115
|
+
Dict containing the complete OpenAPI schema / Словарь с полной схемой OpenAPI
|
97
116
|
"""
|
98
117
|
# Deep copy the base schema to avoid modifying it
|
99
118
|
schema = deepcopy(self.base_schema)
|
100
|
-
|
119
|
+
|
120
|
+
# Optionally override info fields
|
121
|
+
if title:
|
122
|
+
schema["info"]["title"] = title
|
123
|
+
if description:
|
124
|
+
schema["info"]["description"] = description
|
125
|
+
if version:
|
126
|
+
schema["info"]["version"] = version
|
127
|
+
|
101
128
|
# Add commands to schema
|
102
129
|
self._add_commands_to_schema(schema)
|
103
|
-
|
130
|
+
|
104
131
|
logger.info(f"Generated OpenAPI schema with {len(registry.get_all_commands())} commands")
|
105
|
-
|
132
|
+
|
106
133
|
return schema
|
107
134
|
|
108
135
|
|
109
136
|
def custom_openapi(app: FastAPI) -> Dict[str, Any]:
|
110
137
|
"""
|
138
|
+
EN:
|
111
139
|
Create a custom OpenAPI schema for the FastAPI application.
|
140
|
+
Passes app's title, description, and version to the generator.
|
141
|
+
|
142
|
+
RU:
|
143
|
+
Создаёт кастомную OpenAPI-схему для FastAPI-приложения.
|
144
|
+
Передаёт параметры title, description и version из приложения в генератор схемы.
|
112
145
|
|
113
146
|
Args:
|
114
|
-
app: The FastAPI application
|
147
|
+
app: The FastAPI application / FastAPI-приложение
|
115
148
|
|
116
149
|
Returns:
|
117
|
-
Dict containing the custom OpenAPI schema
|
150
|
+
Dict containing the custom OpenAPI schema / Словарь с кастомной OpenAPI-схемой
|
118
151
|
"""
|
119
152
|
generator = CustomOpenAPIGenerator()
|
120
|
-
openapi_schema = generator.generate(
|
121
|
-
|
153
|
+
openapi_schema = generator.generate(
|
154
|
+
title=getattr(app, 'title', None),
|
155
|
+
description=getattr(app, 'description', None),
|
156
|
+
version=getattr(app, 'version', None)
|
157
|
+
)
|
158
|
+
|
122
159
|
# Cache the schema
|
123
160
|
app.openapi_schema = openapi_schema
|
124
|
-
|
161
|
+
|
125
162
|
return openapi_schema
|
@@ -232,4 +232,22 @@ def test_batch_requests(test_client: TestClient, json_rpc_request: Dict[str, Any
|
|
232
232
|
assert data[0]["id"] == "1"
|
233
233
|
|
234
234
|
assert data[1]["result"]["params"] == {"request_id": "2"}
|
235
|
-
assert data[1]["id"] == "2"
|
235
|
+
assert data[1]["id"] == "2"
|
236
|
+
|
237
|
+
|
238
|
+
def test_custom_openapi_schema_fields():
|
239
|
+
"""
|
240
|
+
Test that custom title, description, and version are set in the OpenAPI schema.
|
241
|
+
"""
|
242
|
+
from fastapi import FastAPI
|
243
|
+
from mcp_proxy_adapter.custom_openapi import custom_openapi
|
244
|
+
|
245
|
+
app = FastAPI(
|
246
|
+
title="Custom Title",
|
247
|
+
description="Custom Description",
|
248
|
+
version="9.9.9"
|
249
|
+
)
|
250
|
+
schema = custom_openapi(app)
|
251
|
+
assert schema["info"]["title"] == "Custom Title"
|
252
|
+
assert schema["info"]["description"] == "Custom Description"
|
253
|
+
assert schema["info"]["version"] == "9.9.9"
|
mcp_proxy_adapter/version.py
CHANGED
@@ -29,7 +29,7 @@ examples/complete_example/__init__.py,sha256=JQDNMNOrQAvbQyEV7tV3XrVKBxZRYy3ODMC
|
|
29
29
|
examples/complete_example/config.json,sha256=KbfZnu4SMYH6B7ENQaZ_sZXrWdkmCdMcWgy47nAHh_Q,814
|
30
30
|
examples/complete_example/docker-compose.yml,sha256=kBXjXFeswZCZ4-UhI0vC0OMR_nMRRoDt3PltCi-RGb8,924
|
31
31
|
examples/complete_example/requirements.txt,sha256=QHeMbXMHgkISmFoXfO09kiaXAMkg0nNBdCfwThKiHDc,403
|
32
|
-
examples/complete_example/server.py,sha256=
|
32
|
+
examples/complete_example/server.py,sha256=t-GTqSP0yatjs67O1OFHzf-Yg7tU0aCw6r2eUdYtjpM,3565
|
33
33
|
examples/complete_example/commands/__init__.py,sha256=cZDiwz3nLaeSCwR4oK7xlGgVsXt2WyAlIEMWCxSJPAE,121
|
34
34
|
examples/complete_example/commands/system_command.py,sha256=CwcBRWMODG7Ynr9Syaildu3APuuUdJ_yvQOggAAidg8,10717
|
35
35
|
examples/complete_example/configs/config.dev.yaml,sha256=ASIwU8xzB-kinAsLGghv8-LCER1SUC1ed6K8BktOYPQ,1282
|
@@ -44,15 +44,15 @@ examples/minimal_example/tests/test_hello_command.py,sha256=C48o7Hh_gy2NlLqb2KKm
|
|
44
44
|
examples/minimal_example/tests/test_integration.py,sha256=mW9LEXX5yOCxP3uIpGMiTEMci7DE8PDDCiE8rKJn4ds,6213
|
45
45
|
mcp_proxy_adapter/__init__.py,sha256=B7m1YWyv_Wb87-Q-JqVpHQgwajnfIgDyZ_iIxzdTbBY,1021
|
46
46
|
mcp_proxy_adapter/config.py,sha256=MjgZAld6TiD0F5oCyEaJhYhfEXVZxc5G5ke2SLKCV9A,5748
|
47
|
-
mcp_proxy_adapter/custom_openapi.py,sha256=
|
47
|
+
mcp_proxy_adapter/custom_openapi.py,sha256=a8DidORiO2sxMnRHlgSD0C6_6lZi3K56-PzF2p_t4NE,6316
|
48
48
|
mcp_proxy_adapter/openapi.py,sha256=jyl5EPXcFhzFKEEMXxHeqF1U-SsYvtdlaKGU2QrekpU,13889
|
49
49
|
mcp_proxy_adapter/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
|
-
mcp_proxy_adapter/version.py,sha256=
|
50
|
+
mcp_proxy_adapter/version.py,sha256=n1SIxB1BUfUjywGxxK6RFEDs6vMuHouqenqqD9oFKfg,71
|
51
51
|
mcp_proxy_adapter/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
52
|
mcp_proxy_adapter/api/app.py,sha256=q3yYsNEBFXYr2TOJFxfh6bbF53NkmmgfzSFOtVq7xdc,14353
|
53
53
|
mcp_proxy_adapter/api/handlers.py,sha256=4oAkc-szU3tggkLehqvTW2P5c3HTLIiqXQMwCY0ua2Q,7043
|
54
54
|
mcp_proxy_adapter/api/schemas.py,sha256=xOmiSwHaapY6myEFnLu7o-LWVPM7vwmLYZXFo2c6NfE,12381
|
55
|
-
mcp_proxy_adapter/api/tool_integration.py,sha256=
|
55
|
+
mcp_proxy_adapter/api/tool_integration.py,sha256=mQNFiCkd4plY_A3fkG6auaM8D_1XiC9Jxp4Zrm1ngYE,10161
|
56
56
|
mcp_proxy_adapter/api/tools.py,sha256=nSDXD4rGlFV_NlB91Y0x3N8WeWvWZ76B32-s-VAFARw,8084
|
57
57
|
mcp_proxy_adapter/api/middleware/__init__.py,sha256=RpaA5hbZ7XIjKaQK0PJpZNqc9tFISe5w7ZmqNgwC6FE,1556
|
58
58
|
mcp_proxy_adapter/api/middleware/auth.py,sha256=bic-ez4o4xh74ZczLXSNafrk_m2qk82GF9MHmfDpf9w,4891
|
@@ -91,7 +91,7 @@ mcp_proxy_adapter/tests/commands/test_config_command.py,sha256=ud0Y57xUhFiyrUKDy
|
|
91
91
|
mcp_proxy_adapter/tests/commands/test_echo_command.py,sha256=c2dmqfx3ZfvDedy5vuxArFv7iHsReepMmD2Lchg4l3E,3437
|
92
92
|
mcp_proxy_adapter/tests/commands/test_help_command.py,sha256=OJCZMS0BqUUNNSecipd3dOFokUATiET3gpCoVAxPXPA,4116
|
93
93
|
mcp_proxy_adapter/tests/functional/__init__.py,sha256=muVNR6LD5o7DsDaLrbLTFsavUNcnyM608-mr-dqzgDU,59
|
94
|
-
mcp_proxy_adapter/tests/functional/test_api.py,sha256=
|
94
|
+
mcp_proxy_adapter/tests/functional/test_api.py,sha256=OaGB-WAWVyX4b0b-mCdXBNhwwYABYeBPO3IDnA3I00c,7114
|
95
95
|
mcp_proxy_adapter/tests/integration/__init__.py,sha256=JZpeNG1PBRZ3k5zfq6NH3GyzDc1Yx1ZUgwi6eLBxs1o,60
|
96
96
|
mcp_proxy_adapter/tests/integration/test_cmd_integration.py,sha256=OqBxh52WPijKaRrIHA54QDJQLBz_nwlCywF9k5jxa_Y,3430
|
97
97
|
mcp_proxy_adapter/tests/integration/test_integration.py,sha256=Rf8GTxdZOvZzrtgqWN2fp-36qUU5rpHdV9zhN1JxNw8,6619
|
@@ -102,8 +102,8 @@ mcp_proxy_adapter/tests/stubs/echo_command.py,sha256=Y7SA4IB5Lo_ncn78SDm9iRZvJSK
|
|
102
102
|
mcp_proxy_adapter/tests/unit/__init__.py,sha256=RS-5UoSCcLKtr2jrAaZw_NG9MquA6BZmxq-P6cTw9ok,53
|
103
103
|
mcp_proxy_adapter/tests/unit/test_base_command.py,sha256=ldDXQYk2eijbTgZioSBAhHzSAa_SuBKYqCutCEzUYTE,3924
|
104
104
|
mcp_proxy_adapter/tests/unit/test_config.py,sha256=SZ62LXFOv_fsV0fmSIBdHWvapEyexKrioFRQo0I4pkg,5900
|
105
|
-
mcp_proxy_adapter-3.0.
|
106
|
-
mcp_proxy_adapter-3.0.
|
107
|
-
mcp_proxy_adapter-3.0.
|
108
|
-
mcp_proxy_adapter-3.0.
|
109
|
-
mcp_proxy_adapter-3.0.
|
105
|
+
mcp_proxy_adapter-3.0.3.dist-info/licenses/LICENSE,sha256=OkApFEwdgMCt_mbvUI-eIwKMSTe38K3XnU2DT5ub-wI,1072
|
106
|
+
mcp_proxy_adapter-3.0.3.dist-info/METADATA,sha256=kyCCy5J9i92A38ew7UbqT4Tsy0KAKwPkLu0v00CnfFI,7537
|
107
|
+
mcp_proxy_adapter-3.0.3.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
108
|
+
mcp_proxy_adapter-3.0.3.dist-info/top_level.txt,sha256=kxq3OC7vBtsFdy9dDVse4cOl-SV_QlvcTeSkuw_jw3I,27
|
109
|
+
mcp_proxy_adapter-3.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|