mcp-proxy-adapter 2.1.9__py3-none-any.whl → 2.1.11__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/adapter.py +3 -13
- mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +12 -6
- mcp_proxy_adapter/examples/help_best_practices.py +2 -2
- mcp_proxy_adapter/examples/help_usage.py +12 -12
- mcp_proxy_adapter/examples/openapi_server.py +86 -100
- {mcp_proxy_adapter-2.1.9.dist-info → mcp_proxy_adapter-2.1.11.dist-info}/METADATA +1 -1
- {mcp_proxy_adapter-2.1.9.dist-info → mcp_proxy_adapter-2.1.11.dist-info}/RECORD +10 -10
- {mcp_proxy_adapter-2.1.9.dist-info → mcp_proxy_adapter-2.1.11.dist-info}/WHEEL +0 -0
- {mcp_proxy_adapter-2.1.9.dist-info → mcp_proxy_adapter-2.1.11.dist-info}/licenses/LICENSE +0 -0
- {mcp_proxy_adapter-2.1.9.dist-info → mcp_proxy_adapter-2.1.11.dist-info}/top_level.txt +0 -0
mcp_proxy_adapter/adapter.py
CHANGED
@@ -493,13 +493,6 @@ class MCPProxyAdapter:
|
|
493
493
|
"details": "Request requires 'command', 'method' or 'params' field"
|
494
494
|
}
|
495
495
|
}
|
496
|
-
# Подмена help -> __help
|
497
|
-
if command == "help":
|
498
|
-
command = "__help"
|
499
|
-
# Переименовываем параметр внутри params
|
500
|
-
if "command" in params:
|
501
|
-
params["cmdname"] = params.pop("command")
|
502
|
-
logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
|
503
496
|
|
504
497
|
# Check if command exists
|
505
498
|
if command not in self.registry.dispatcher.get_valid_commands():
|
@@ -508,14 +501,12 @@ class MCPProxyAdapter:
|
|
508
501
|
"error": {
|
509
502
|
"code": 404,
|
510
503
|
"message": f"Unknown command: {command}",
|
511
|
-
"details": f"
|
504
|
+
"details": f"Command '{command}' not found in registry. Available commands: {', '.join(self.registry.dispatcher.get_valid_commands())}"
|
512
505
|
}
|
513
506
|
}
|
514
507
|
|
515
|
-
logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
|
516
508
|
# Check for required parameters
|
517
509
|
command_info = self.registry.dispatcher.get_command_info(command)
|
518
|
-
logger.info(f"[DEBUG] MCP CMD: command_info={command_info}")
|
519
510
|
if command_info and "params" in command_info:
|
520
511
|
missing_params = []
|
521
512
|
for param_name, param_info in command_info["params"].items():
|
@@ -531,7 +522,7 @@ class MCPProxyAdapter:
|
|
531
522
|
"details": f"Command '{command}' requires following parameters: {', '.join(missing_params)}"
|
532
523
|
}
|
533
524
|
}
|
534
|
-
|
525
|
+
|
535
526
|
# Check parameter types
|
536
527
|
type_errors = self._validate_param_types(command, params)
|
537
528
|
if type_errors:
|
@@ -543,10 +534,9 @@ class MCPProxyAdapter:
|
|
543
534
|
"details": "Check parameter types and try again"
|
544
535
|
}
|
545
536
|
}
|
546
|
-
|
537
|
+
|
547
538
|
# Execute the command
|
548
539
|
try:
|
549
|
-
logger.info(f"[DEBUG] MCP CMD: executing command={command}, params={params}")
|
550
540
|
result = self.registry.dispatcher.execute(command, **params)
|
551
541
|
|
552
542
|
# Return result in MCP Proxy format
|
@@ -157,26 +157,31 @@ class JsonRpcDispatcher(BaseDispatcher):
|
|
157
157
|
def _help_command(self, params: Dict[str, Any] = None) -> Dict[str, Any]:
|
158
158
|
"""
|
159
159
|
Built-in help command for getting command information.
|
160
|
+
|
160
161
|
Args:
|
161
|
-
params: Command parameters
|
162
|
+
params: Command parameters
|
162
163
|
cmdname: Command name for detailed information
|
164
|
+
|
163
165
|
Returns:
|
164
166
|
Dict[str, Any]: Command help information
|
165
167
|
"""
|
166
|
-
if params
|
168
|
+
if not params:
|
167
169
|
params = {}
|
168
|
-
|
169
|
-
|
170
|
-
if cmdname:
|
170
|
+
|
171
|
+
# Only support 'cmdname' parameter
|
172
|
+
if "cmdname" in params and params["cmdname"]:
|
173
|
+
cmdname = params["cmdname"]
|
171
174
|
if cmdname not in self._metadata:
|
172
175
|
return {
|
173
176
|
"error": f"Command '{cmdname}' not found",
|
174
177
|
"available_commands": list(self._metadata.keys())
|
175
178
|
}
|
179
|
+
|
176
180
|
return {
|
177
181
|
"cmdname": cmdname,
|
178
182
|
"info": self._metadata[cmdname]
|
179
183
|
}
|
184
|
+
|
180
185
|
# Otherwise return brief information about all commands
|
181
186
|
commands_info = {}
|
182
187
|
for cmd, info in self._metadata.items():
|
@@ -185,8 +190,9 @@ class JsonRpcDispatcher(BaseDispatcher):
|
|
185
190
|
"description": info["description"],
|
186
191
|
"params_count": len(info["params"])
|
187
192
|
}
|
193
|
+
|
188
194
|
return {
|
189
195
|
"commands": commands_info,
|
190
196
|
"total": len(commands_info),
|
191
|
-
"note": "
|
197
|
+
"note": "To get info about a specific command, call help with parameter: POST /cmd {\"command\": \"help\", \"params\": {\"cmdname\": \"<command_name>\"}}. Only the 'cmdname' parameter is supported. Calling 'help <command>' (with space) is NOT supported."
|
192
198
|
}
|
@@ -12,10 +12,10 @@ Run:
|
|
12
12
|
"""
|
13
13
|
import os
|
14
14
|
import sys
|
15
|
-
sys.path.insert(0, os.path.abspath(os.path.
|
15
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
|
16
16
|
from typing import Any, Dict
|
17
17
|
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
18
|
-
from
|
18
|
+
from mcp_proxy_adapter.testing_utils import MockRegistry
|
19
19
|
|
20
20
|
# --- Setup registry and adapter ---
|
21
21
|
registry = MockRegistry()
|
@@ -12,41 +12,41 @@ Run:
|
|
12
12
|
"""
|
13
13
|
import os
|
14
14
|
import sys
|
15
|
-
sys.path.insert(0, os.path.abspath(os.path.
|
15
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
|
16
16
|
from typing import Any, Dict
|
17
17
|
|
18
18
|
# Assume MCPProxyAdapter and MockRegistry are available from src and tests
|
19
19
|
from mcp_proxy_adapter.adapter import MCPProxyAdapter
|
20
|
-
from
|
20
|
+
from mcp_proxy_adapter.testing_utils import MockRegistry
|
21
21
|
|
22
22
|
# --- Setup registry and adapter ---
|
23
23
|
registry = MockRegistry()
|
24
24
|
adapter = MCPProxyAdapter(registry)
|
25
25
|
|
26
26
|
# --- Best practice: always check if 'help' is in commands ---
|
27
|
-
def call_help(
|
27
|
+
def call_help(cmdname: str = None) -> Dict[str, Any]:
|
28
28
|
"""Call help command with or without parameter."""
|
29
29
|
dispatcher = registry.dispatcher
|
30
30
|
if "help" in dispatcher.get_valid_commands():
|
31
|
-
if
|
31
|
+
if cmdname:
|
32
32
|
try:
|
33
|
-
return dispatcher.help_command(
|
33
|
+
return dispatcher.help_command(cmdname=cmdname)
|
34
34
|
except Exception as e:
|
35
35
|
print(f"Project help failed: {e}. Fallback to adapter help.")
|
36
|
-
return adapter_help(
|
36
|
+
return adapter_help(cmdname)
|
37
37
|
else:
|
38
38
|
return dispatcher.help_command()
|
39
39
|
else:
|
40
|
-
return adapter_help(
|
40
|
+
return adapter_help(cmdname)
|
41
41
|
|
42
|
-
def adapter_help(
|
42
|
+
def adapter_help(cmdname: str = None) -> Dict[str, Any]:
|
43
43
|
"""Fallback: call adapter's help (simulate)."""
|
44
44
|
dispatcher = registry.dispatcher
|
45
|
-
if not
|
45
|
+
if not cmdname:
|
46
46
|
return {"source": "adapter", "commands": dispatcher.get_valid_commands()}
|
47
|
-
if
|
48
|
-
return {"source": "adapter", "
|
49
|
-
return {"source": "adapter", "error": f"Command '{
|
47
|
+
if cmdname in dispatcher.get_valid_commands():
|
48
|
+
return {"source": "adapter", "cmdname": cmdname, "info": {"description": "Adapter help for command"}}
|
49
|
+
return {"source": "adapter", "error": f"Command '{cmdname}' not found (adapter)", "available_commands": dispatcher.get_valid_commands()}
|
50
50
|
|
51
51
|
if __name__ == "__main__":
|
52
52
|
print("=== Project help (no param) ===")
|
@@ -171,7 +171,7 @@ class MockDispatcher:
|
|
171
171
|
"help": {
|
172
172
|
"description": "Show information about available commands or a specific command.",
|
173
173
|
"params": {
|
174
|
-
"
|
174
|
+
"cmdname": {
|
175
175
|
"type": "string",
|
176
176
|
"description": "Command name for detailed info",
|
177
177
|
"required": False
|
@@ -278,119 +278,105 @@ class MockDispatcher:
|
|
278
278
|
|
279
279
|
def help_command(self, **params):
|
280
280
|
"""Return info about all commands or a specific command."""
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
info = self.commands_info.get(command)
|
281
|
+
cmdname = params.get("cmdname")
|
282
|
+
if cmdname:
|
283
|
+
info = self.commands_info.get(cmdname)
|
285
284
|
if info:
|
286
|
-
return {"
|
285
|
+
return {"cmdname": cmdname, "info": info}
|
287
286
|
else:
|
288
|
-
return {"error": f"Command '{
|
289
|
-
# Если параметр
|
287
|
+
return {"error": f"Command '{cmdname}' not found", "available_commands": list(self.commands_info.keys())}
|
288
|
+
# Если параметр cmdname не указан, возвращаем краткую информацию обо всех
|
290
289
|
return {
|
291
290
|
"commands": {cmd: {"description": info["description"], "params": info["params"]} for cmd, info in self.commands_info.items()},
|
292
291
|
"total": len(self.commands_info),
|
293
|
-
"note": "Use the '
|
292
|
+
"note": "Use the 'cmdname' parameter to get detailed information about a specific command"
|
294
293
|
}
|
295
294
|
|
295
|
+
# --- Создание registry и FastAPI-приложения на верхнем уровне ---
|
296
296
|
class CustomMockRegistry(MockRegistry):
|
297
297
|
"""Custom command registry for example."""
|
298
|
-
|
299
298
|
def __init__(self):
|
300
|
-
"""Initialization with custom dispatcher."""
|
301
299
|
self.dispatcher = MockDispatcher()
|
302
300
|
self.generators = []
|
303
301
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
"""Root endpoint."""
|
341
|
-
return {
|
342
|
-
"message": "OpenAPI Server Example with MCP Proxy Adapter integration",
|
343
|
-
"endpoints": {
|
344
|
-
"items": "/items",
|
345
|
-
"item": "/items/{item_id}",
|
346
|
-
"search": "/items/search",
|
347
|
-
"mcp_proxy": "/cmd"
|
348
|
-
}
|
302
|
+
registry = CustomMockRegistry()
|
303
|
+
app = FastAPI(
|
304
|
+
title="OpenAPI Server Example",
|
305
|
+
description="Example OpenAPI server with MCP Proxy Adapter integration",
|
306
|
+
version="1.0.0"
|
307
|
+
)
|
308
|
+
|
309
|
+
# Configure CORS
|
310
|
+
from fastapi.middleware.cors import CORSMiddleware
|
311
|
+
app.add_middleware(
|
312
|
+
CORSMiddleware,
|
313
|
+
allow_origins=["*"],
|
314
|
+
allow_credentials=True,
|
315
|
+
allow_methods=["*"],
|
316
|
+
allow_headers=["*"],
|
317
|
+
)
|
318
|
+
|
319
|
+
# Create MCP Proxy adapter with explicit endpoint
|
320
|
+
adapter = MCPProxyAdapter(registry, cmd_endpoint="/cmd")
|
321
|
+
# Register adapter endpoints
|
322
|
+
adapter.register_endpoints(app)
|
323
|
+
# Save MCP Proxy configuration to file
|
324
|
+
config_path = os.path.join(os.path.dirname(__file__), "mcp_proxy_config.json")
|
325
|
+
adapter.save_config_to_file(config_path)
|
326
|
+
logger.info(f"MCP Proxy configuration saved to {config_path}")
|
327
|
+
|
328
|
+
# --- REST endpoints ---
|
329
|
+
@app.get("/")
|
330
|
+
def read_root():
|
331
|
+
return {
|
332
|
+
"message": "OpenAPI Server Example with MCP Proxy Adapter integration",
|
333
|
+
"endpoints": {
|
334
|
+
"items": "/items",
|
335
|
+
"item": "/items/{item_id}",
|
336
|
+
"search": "/items/search",
|
337
|
+
"mcp_proxy": "/cmd"
|
349
338
|
}
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
""
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
return registry.dispatcher.search_items(keyword)
|
392
|
-
|
393
|
-
# Start server
|
339
|
+
}
|
340
|
+
|
341
|
+
@app.get("/items", response_model=List[Item])
|
342
|
+
def read_items():
|
343
|
+
return items_db
|
344
|
+
|
345
|
+
@app.get("/items/{item_id}", response_model=Item)
|
346
|
+
def read_item(item_id: int = Path(..., description="Item ID", gt=0)):
|
347
|
+
try:
|
348
|
+
return registry.dispatcher.get_item(item_id)
|
349
|
+
except ValueError as e:
|
350
|
+
return {"error": str(e)}
|
351
|
+
|
352
|
+
@app.post("/items", response_model=Item)
|
353
|
+
def create_new_item(item: Item = Body(..., description="Data of new item")):
|
354
|
+
return registry.dispatcher.create_item(item.model_dump())
|
355
|
+
|
356
|
+
@app.put("/items/{item_id}", response_model=Item)
|
357
|
+
def update_existing_item(
|
358
|
+
item_id: int = Path(..., description="Item ID to update", gt=0),
|
359
|
+
item: Item = Body(..., description="Updated item data")
|
360
|
+
):
|
361
|
+
try:
|
362
|
+
return registry.dispatcher.update_item(item_id, item.model_dump())
|
363
|
+
except ValueError as e:
|
364
|
+
return {"error": str(e)}
|
365
|
+
|
366
|
+
@app.delete("/items/{item_id}")
|
367
|
+
def delete_existing_item(item_id: int = Path(..., description="Item ID to delete", gt=0)):
|
368
|
+
try:
|
369
|
+
return registry.dispatcher.delete_item(item_id)
|
370
|
+
except ValueError as e:
|
371
|
+
return {"error": str(e)}
|
372
|
+
|
373
|
+
@app.get("/items/search", response_model=List[Item])
|
374
|
+
def search_items_by_keyword(keyword: str = Query(..., description="Search keyword")):
|
375
|
+
return registry.dispatcher.search_items(keyword)
|
376
|
+
|
377
|
+
# --- main() только для запуска через python ---
|
378
|
+
def main():
|
379
|
+
import uvicorn
|
394
380
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
395
381
|
|
396
382
|
if __name__ == "__main__":
|
@@ -1,5 +1,5 @@
|
|
1
1
|
mcp_proxy_adapter/__init__.py,sha256=_6D-TfANWp9zc550M5LUeGPvioFqG1bAl3tZj-gNmJU,463
|
2
|
-
mcp_proxy_adapter/adapter.py,sha256=
|
2
|
+
mcp_proxy_adapter/adapter.py,sha256=76dkVeDuqLsJ5AhuftzLlwy2M6yr_PfNbmNfo9dXVhc,28844
|
3
3
|
mcp_proxy_adapter/models.py,sha256=acqVQBYAojHXeJ1MJyvpMyT6-J6aMxWuZMszn_-RsOU,2338
|
4
4
|
mcp_proxy_adapter/registry.py,sha256=jgC4TKaPbMbAsoxvGp2ToaOE4drD-VfZug7WJbm4IW4,15853
|
5
5
|
mcp_proxy_adapter/schema.py,sha256=HZM0TTQTSi8ha1TEeVevdCyGZOUPoT1soB7Nex0hV50,10947
|
@@ -9,21 +9,21 @@ mcp_proxy_adapter/analyzers/docstring_analyzer.py,sha256=T3FLJEo_uChShfiEKRl8GpV
|
|
9
9
|
mcp_proxy_adapter/analyzers/type_analyzer.py,sha256=6Wac7osKwF03waFSwQ8ZM0Wqn_zAP2D-I4WMEpR0hQM,5230
|
10
10
|
mcp_proxy_adapter/dispatchers/__init__.py,sha256=FWgimgInGphIjCEnvA3-ZExiapUzYAVis2H9C5IWivU,365
|
11
11
|
mcp_proxy_adapter/dispatchers/base_dispatcher.py,sha256=S5_Xri058jAmOWeit1tedB_GMZQ9RLcNcYabA83ZF6k,2288
|
12
|
-
mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py,sha256=
|
12
|
+
mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py,sha256=S98qSj0p3glfiPcRirqCZaoiD9PrVVM3t7Lrgd6S8kM,6461
|
13
13
|
mcp_proxy_adapter/examples/analyze_config.py,sha256=vog7TNHDw5ZoYhQLbAvZvEoufmQwH54KJzQBJrSq5w4,4283
|
14
14
|
mcp_proxy_adapter/examples/basic_integration.py,sha256=w_oA777YiQt36gzI113KPQ6k45caXbMCqW9hD8sy8zo,4657
|
15
15
|
mcp_proxy_adapter/examples/docstring_and_schema_example.py,sha256=c96L4KF_7yWzffmvd4hyeQuXSdYyYkv7Uvuy0QxgMcQ,1929
|
16
16
|
mcp_proxy_adapter/examples/extension_example.py,sha256=vnatnFdNTapMpPcQ79Ugitk92ZiUfpLTs7Dvsodf1og,2277
|
17
|
-
mcp_proxy_adapter/examples/help_best_practices.py,sha256=
|
18
|
-
mcp_proxy_adapter/examples/help_usage.py,sha256=
|
17
|
+
mcp_proxy_adapter/examples/help_best_practices.py,sha256=Bit9Ywl9vGvM_kuV8DJ6pIDK4mY4mF2Gia9rLc56RpI,2646
|
18
|
+
mcp_proxy_adapter/examples/help_usage.py,sha256=9-65TyECtQYqPJLG3tlOWctI1zoCh6dEewh_i8mCdus,2577
|
19
19
|
mcp_proxy_adapter/examples/mcp_proxy_client.py,sha256=z4IzFlGigVTQSb8TpcrQ_a0migsmC58LnNwc8wZmTfw,3811
|
20
|
-
mcp_proxy_adapter/examples/openapi_server.py,sha256=
|
20
|
+
mcp_proxy_adapter/examples/openapi_server.py,sha256=KjUkXnGMnCxiRd71b1NFoHf40y9REXFqnmaxAgK4FB8,13229
|
21
21
|
mcp_proxy_adapter/examples/project_structure_example.py,sha256=sswTo6FZb1F5juHa0FYG3cgvrh3wfgGfJu2bBy5tCm4,1460
|
22
22
|
mcp_proxy_adapter/examples/testing_example.py,sha256=AB13c4C1bjs1145O-yriwyreeVXtMOlQLzs2BCGmprk,1719
|
23
23
|
mcp_proxy_adapter/validators/docstring_validator.py,sha256=Onpq2iNJ1qF4ejkJJIlBkLROuSNIVALHVmXIgkCpaFI,2934
|
24
24
|
mcp_proxy_adapter/validators/metadata_validator.py,sha256=uCrn38-VYYn89l6f5CC_GoTAHAweaOW2Z6Esro1rtGw,3155
|
25
|
-
mcp_proxy_adapter-2.1.
|
26
|
-
mcp_proxy_adapter-2.1.
|
27
|
-
mcp_proxy_adapter-2.1.
|
28
|
-
mcp_proxy_adapter-2.1.
|
29
|
-
mcp_proxy_adapter-2.1.
|
25
|
+
mcp_proxy_adapter-2.1.11.dist-info/licenses/LICENSE,sha256=OkApFEwdgMCt_mbvUI-eIwKMSTe38K3XnU2DT5ub-wI,1072
|
26
|
+
mcp_proxy_adapter-2.1.11.dist-info/METADATA,sha256=2Z-WGz0AwAtHoUkUDhvQ1B_3enFmOj7epWGpm4C7UZo,12579
|
27
|
+
mcp_proxy_adapter-2.1.11.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
|
28
|
+
mcp_proxy_adapter-2.1.11.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
|
29
|
+
mcp_proxy_adapter-2.1.11.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|