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.
@@ -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"Unknown command: {command}. Available commands: {', '.join(self.registry.dispatcher.get_valid_commands())}"
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
- logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
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
- logger.info(f"[DEBUG] MCP CMD: command={command}, params={params}")
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 (dict)
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 is None:
168
+ if not params:
167
169
  params = {}
168
- # If specific command is specified, return information only about it
169
- cmdname = params.get("cmdname")
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": "Use the 'cmdname' parameter to get detailed information about a specific command"
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.dirname(os.path.dirname(__file__))))
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 tests.test_mcp_proxy_adapter import MockRegistry
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.dirname(os.path.dirname(__file__))))
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 tests.test_mcp_proxy_adapter import MockRegistry
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(command: str = None) -> Dict[str, Any]:
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 command:
31
+ if cmdname:
32
32
  try:
33
- return dispatcher.help_command(command=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(command)
36
+ return adapter_help(cmdname)
37
37
  else:
38
38
  return dispatcher.help_command()
39
39
  else:
40
- return adapter_help(command)
40
+ return adapter_help(cmdname)
41
41
 
42
- def adapter_help(command: str = None) -> Dict[str, Any]:
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 command:
45
+ if not cmdname:
46
46
  return {"source": "adapter", "commands": dispatcher.get_valid_commands()}
47
- if command in dispatcher.get_valid_commands():
48
- return {"source": "adapter", "command": command, "info": {"description": "Adapter help for command"}}
49
- return {"source": "adapter", "error": f"Command '{command}' not found (adapter)", "available_commands": dispatcher.get_valid_commands()}
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
- "command": {
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
- # Если в будущем появится пользовательская команда help, можно реализовать её здесь
282
- command = params.get("command")
283
- if command:
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 {"command": command, "info": info}
285
+ return {"cmdname": cmdname, "info": info}
287
286
  else:
288
- return {"error": f"Command '{command}' not found", "available_commands": list(self.commands_info.keys())}
289
- # Если параметр command не указан, возвращаем краткую информацию обо всех
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 'command' parameter to get detailed information about a specific command"
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
- def main():
305
- """Main function to start server."""
306
- # Create command registry
307
- registry = CustomMockRegistry()
308
-
309
- # Create FastAPI object
310
- app = FastAPI(
311
- title="OpenAPI Server Example",
312
- description="Example OpenAPI server with MCP Proxy Adapter integration",
313
- version="1.0.0"
314
- )
315
-
316
- # Configure CORS
317
- from fastapi.middleware.cors import CORSMiddleware
318
- app.add_middleware(
319
- CORSMiddleware,
320
- allow_origins=["*"], # Allow requests from all sources
321
- allow_credentials=True,
322
- allow_methods=["*"], # Allow all methods
323
- allow_headers=["*"], # Allow all headers
324
- )
325
-
326
- # Create MCP Proxy adapter with explicit endpoint
327
- adapter = MCPProxyAdapter(registry, cmd_endpoint="/cmd")
328
-
329
- # Register adapter endpoints
330
- adapter.register_endpoints(app)
331
-
332
- # Save MCP Proxy configuration to file
333
- config_path = os.path.join(os.path.dirname(__file__), "mcp_proxy_config.json")
334
- adapter.save_config_to_file(config_path)
335
- logger.info(f"MCP Proxy configuration saved to {config_path}")
336
-
337
- # Define REST endpoints for example (not related to MCP Proxy)
338
- @app.get("/")
339
- def read_root():
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
- @app.get("/items", response_model=List[Item])
352
- def read_items():
353
- """Get all items."""
354
- return items_db
355
-
356
- @app.get("/items/{item_id}", response_model=Item)
357
- def read_item(item_id: int = Path(..., description="Item ID", gt=0)):
358
- """Get item by ID."""
359
- try:
360
- return registry.dispatcher.get_item(item_id)
361
- except ValueError as e:
362
- return {"error": str(e)}
363
-
364
- @app.post("/items", response_model=Item)
365
- def create_new_item(item: Item = Body(..., description="Data of new item")):
366
- """Create new item."""
367
- return registry.dispatcher.create_item(item.model_dump())
368
-
369
- @app.put("/items/{item_id}", response_model=Item)
370
- def update_existing_item(
371
- item_id: int = Path(..., description="Item ID to update", gt=0),
372
- item: Item = Body(..., description="Updated item data")
373
- ):
374
- """Update item by ID."""
375
- try:
376
- return registry.dispatcher.update_item(item_id, item.model_dump())
377
- except ValueError as e:
378
- return {"error": str(e)}
379
-
380
- @app.delete("/items/{item_id}")
381
- def delete_existing_item(item_id: int = Path(..., description="Item ID to delete", gt=0)):
382
- """Delete item by ID."""
383
- try:
384
- return registry.dispatcher.delete_item(item_id)
385
- except ValueError as e:
386
- return {"error": str(e)}
387
-
388
- @app.get("/items/search", response_model=List[Item])
389
- def search_items_by_keyword(keyword: str = Query(..., description="Search keyword")):
390
- """Search items by keyword."""
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-proxy-adapter
3
- Version: 2.1.9
3
+ Version: 2.1.11
4
4
  Summary: Adapter for exposing Command Registry commands as tools for AI models via MCP Proxy.
5
5
  Home-page: https://github.com/vasilyvz/mcp-proxy-adapter
6
6
  Author: Vasiliy VZ
@@ -1,5 +1,5 @@
1
1
  mcp_proxy_adapter/__init__.py,sha256=_6D-TfANWp9zc550M5LUeGPvioFqG1bAl3tZj-gNmJU,463
2
- mcp_proxy_adapter/adapter.py,sha256=XQGhht_lhLH7eaSAgoxl4NdbT1MwMW5mwDrTJMXl8pk,29631
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=Iv7Z4GX5Wy6gGNESEYqjLnrPvxPYXa9WJiwaTSKMjg0,6238
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=wUtZRnAktnpfAc9vAvqSxUquHEr5ewaPDPyc6BoCqdQ,2637
18
- mcp_proxy_adapter/examples/help_usage.py,sha256=UOd3HJeYlQpQkAyceGNm66jXX_h-T05pjIGD-b7-Pfg,2568
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=MXCr5qifI03oexgdY05SsnbhWCe2_6ebnYOfAdk_Uug,14027
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.9.dist-info/licenses/LICENSE,sha256=OkApFEwdgMCt_mbvUI-eIwKMSTe38K3XnU2DT5ub-wI,1072
26
- mcp_proxy_adapter-2.1.9.dist-info/METADATA,sha256=nZ4aznn1akyMf7bPXO3kQb0Az6FiOx2hoCssFuvM05Y,12578
27
- mcp_proxy_adapter-2.1.9.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
28
- mcp_proxy_adapter-2.1.9.dist-info/top_level.txt,sha256=JZT7vPLBYrtroX-ij68JBhJYbjDdghcV-DFySRy-Nnw,18
29
- mcp_proxy_adapter-2.1.9.dist-info/RECORD,,
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,,