mcp-proxy-adapter 2.1.16__py3-none-any.whl → 3.0.0__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.
Files changed (84) hide show
  1. examples/__init__.py +19 -0
  2. examples/anti_patterns/README.md +51 -0
  3. examples/anti_patterns/__init__.py +9 -0
  4. examples/anti_patterns/bad_design/README.md +72 -0
  5. examples/anti_patterns/bad_design/global_state.py +170 -0
  6. examples/anti_patterns/bad_design/monolithic_command.py +272 -0
  7. examples/basic_example/README.md +131 -0
  8. examples/basic_example/__init__.py +8 -0
  9. examples/basic_example/commands/__init__.py +5 -0
  10. examples/basic_example/commands/echo_command.py +95 -0
  11. examples/basic_example/commands/math_command.py +151 -0
  12. examples/basic_example/commands/time_command.py +152 -0
  13. examples/basic_example/config.json +21 -0
  14. examples/basic_example/config.yaml +20 -0
  15. examples/basic_example/docs/EN/README.md +136 -0
  16. examples/basic_example/docs/RU/README.md +136 -0
  17. examples/basic_example/main.py +50 -0
  18. examples/basic_example/server.py +45 -0
  19. examples/basic_example/tests/conftest.py +243 -0
  20. examples/commands/echo_command.py +52 -0
  21. examples/commands/echo_result.py +65 -0
  22. examples/commands/get_date_command.py +98 -0
  23. examples/commands/new_uuid4_command.py +91 -0
  24. examples/complete_example/Dockerfile +24 -0
  25. examples/complete_example/README.md +92 -0
  26. examples/complete_example/__init__.py +8 -0
  27. examples/complete_example/commands/__init__.py +5 -0
  28. examples/complete_example/commands/system_command.py +327 -0
  29. examples/complete_example/config.json +41 -0
  30. examples/complete_example/configs/config.dev.yaml +40 -0
  31. examples/complete_example/configs/config.docker.yaml +40 -0
  32. examples/complete_example/docker-compose.yml +35 -0
  33. examples/complete_example/main.py +67 -0
  34. examples/complete_example/requirements.txt +20 -0
  35. examples/complete_example/server.py +85 -0
  36. examples/minimal_example/README.md +51 -0
  37. examples/minimal_example/__init__.py +8 -0
  38. examples/minimal_example/config.json +21 -0
  39. examples/minimal_example/config.yaml +26 -0
  40. examples/minimal_example/main.py +67 -0
  41. examples/minimal_example/simple_server.py +124 -0
  42. examples/minimal_example/tests/conftest.py +171 -0
  43. examples/minimal_example/tests/test_hello_command.py +111 -0
  44. examples/minimal_example/tests/test_integration.py +183 -0
  45. examples/server.py +69 -0
  46. examples/simple_server.py +137 -0
  47. examples/test_server.py +126 -0
  48. mcp_proxy_adapter/__init__.py +33 -1
  49. mcp_proxy_adapter/config.py +186 -0
  50. mcp_proxy_adapter/custom_openapi.py +125 -0
  51. mcp_proxy_adapter/framework.py +109 -0
  52. mcp_proxy_adapter/openapi.py +403 -0
  53. mcp_proxy_adapter/version.py +3 -0
  54. mcp_proxy_adapter-3.0.0.dist-info/METADATA +200 -0
  55. mcp_proxy_adapter-3.0.0.dist-info/RECORD +58 -0
  56. {mcp_proxy_adapter-2.1.16.dist-info → mcp_proxy_adapter-3.0.0.dist-info}/top_level.txt +1 -0
  57. mcp_proxy_adapter/adapter.py +0 -697
  58. mcp_proxy_adapter/analyzers/__init__.py +0 -1
  59. mcp_proxy_adapter/analyzers/docstring_analyzer.py +0 -199
  60. mcp_proxy_adapter/analyzers/type_analyzer.py +0 -151
  61. mcp_proxy_adapter/dispatchers/__init__.py +0 -1
  62. mcp_proxy_adapter/dispatchers/base_dispatcher.py +0 -85
  63. mcp_proxy_adapter/dispatchers/json_rpc_dispatcher.py +0 -235
  64. mcp_proxy_adapter/examples/analyze_config.py +0 -141
  65. mcp_proxy_adapter/examples/basic_integration.py +0 -155
  66. mcp_proxy_adapter/examples/docstring_and_schema_example.py +0 -69
  67. mcp_proxy_adapter/examples/extension_example.py +0 -72
  68. mcp_proxy_adapter/examples/help_best_practices.py +0 -67
  69. mcp_proxy_adapter/examples/help_usage.py +0 -64
  70. mcp_proxy_adapter/examples/mcp_proxy_client.py +0 -131
  71. mcp_proxy_adapter/examples/openapi_server.py +0 -383
  72. mcp_proxy_adapter/examples/project_structure_example.py +0 -47
  73. mcp_proxy_adapter/examples/testing_example.py +0 -64
  74. mcp_proxy_adapter/models.py +0 -47
  75. mcp_proxy_adapter/registry.py +0 -439
  76. mcp_proxy_adapter/schema.py +0 -257
  77. mcp_proxy_adapter/testing_utils.py +0 -112
  78. mcp_proxy_adapter/validators/__init__.py +0 -1
  79. mcp_proxy_adapter/validators/docstring_validator.py +0 -75
  80. mcp_proxy_adapter/validators/metadata_validator.py +0 -76
  81. mcp_proxy_adapter-2.1.16.dist-info/METADATA +0 -341
  82. mcp_proxy_adapter-2.1.16.dist-info/RECORD +0 -30
  83. {mcp_proxy_adapter-2.1.16.dist-info → mcp_proxy_adapter-3.0.0.dist-info}/WHEEL +0 -0
  84. {mcp_proxy_adapter-2.1.16.dist-info → mcp_proxy_adapter-3.0.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,141 +0,0 @@
1
- """
2
- Analysis of MCP Proxy configuration generated by the adapter.
3
-
4
- This script loads and analyzes the MCP Proxy configuration file
5
- that was created by MCPProxyAdapter, and outputs structured
6
- information about routes and tools.
7
-
8
- Usage:
9
- python examples/analyze_config.py
10
- """
11
- import os
12
- import json
13
- import sys
14
- from typing import Dict, Any, List
15
-
16
-
17
- def load_config_file(config_path: str) -> Dict[str, Any]:
18
- """
19
- Loads MCP Proxy configuration file.
20
-
21
- Args:
22
- config_path (str): Path to configuration file
23
-
24
- Returns:
25
- Dict[str, Any]: Loaded configuration
26
-
27
- Raises:
28
- FileNotFoundError: If file is not found
29
- json.JSONDecodeError: If file is not valid JSON
30
- """
31
- try:
32
- with open(config_path, 'r', encoding='utf-8') as f:
33
- return json.load(f)
34
- except FileNotFoundError:
35
- print(f"Error: Configuration file not found: {config_path}")
36
- sys.exit(1)
37
- except json.JSONDecodeError as e:
38
- print(f"Error: File is not valid JSON: {e}")
39
- sys.exit(1)
40
-
41
-
42
- def print_routes(config: Dict[str, Any]) -> None:
43
- """
44
- Prints route information from configuration.
45
-
46
- Args:
47
- config (Dict[str, Any]): MCP Proxy configuration
48
- """
49
- if "routes" not in config:
50
- print("No routes in configuration")
51
- return
52
-
53
- routes = config["routes"]
54
- print(f"=== Routes ({len(routes)}) ===")
55
-
56
- for i, route in enumerate(routes, 1):
57
- print(f"\n{i}. Route:")
58
- print(f" Endpoint: {route.get('endpoint', 'Not specified')}")
59
- print(f" Method: {route.get('method', 'Not specified')}")
60
-
61
- if "json_rpc" in route:
62
- print(" Type: JSON-RPC")
63
- if "params" in route["json_rpc"]:
64
- print(f" Parameters: {route['json_rpc'].get('params', 'Not specified')}")
65
- else:
66
- print(" Type: Regular HTTP")
67
-
68
-
69
- def print_tools(config: Dict[str, Any]) -> None:
70
- """
71
- Prints tool information from configuration.
72
-
73
- Args:
74
- config (Dict[str, Any]): MCP Proxy configuration
75
- """
76
- if "tools" not in config:
77
- print("No tools in configuration")
78
- return
79
-
80
- tools = config["tools"]
81
- print(f"\n=== Tools ({len(tools)}) ===")
82
-
83
- for i, tool in enumerate(tools, 1):
84
- print(f"\n{i}. Tool:")
85
- print(f" Name: {tool.get('name', 'Not specified')}")
86
- print(f" Description: {tool.get('description', 'Not specified')}")
87
-
88
- if "parameters" in tool:
89
- params = tool["parameters"]
90
- required_params = params.get("required", [])
91
- properties = params.get("properties", {})
92
-
93
- print(f" Parameters ({len(properties)}):")
94
- for param_name, param_info in properties.items():
95
- required = "Required" if param_name in required_params else "Optional"
96
- param_type = param_info.get("type", "Not specified")
97
- description = param_info.get("description", "Not specified")
98
-
99
- print(f" - {param_name} ({param_type}, {required}):")
100
- print(f" {description}")
101
-
102
-
103
- def analyze_config(config_path: str) -> None:
104
- """
105
- Analyzes MCP Proxy configuration.
106
-
107
- Args:
108
- config_path (str): Path to configuration file
109
- """
110
- config = load_config_file(config_path)
111
-
112
- print("\n=== MCP Proxy Configuration Analysis ===")
113
- print(f"File: {config_path}")
114
- print(f"Version: {config.get('version', 'Not specified')}")
115
-
116
- print_routes(config)
117
- print_tools(config)
118
-
119
- print("\n=== Summary ===")
120
- num_routes = len(config.get("routes", []))
121
- num_tools = len(config.get("tools", []))
122
-
123
- print(f"Configuration contains {num_routes} routes and {num_tools} tools.")
124
-
125
- if num_tools > 0 and num_routes > 0:
126
- print("MCP Proxy is configured correctly and ready to use.")
127
- else:
128
- print("WARNING: Configuration may be incomplete or incorrect.")
129
-
130
-
131
- def main():
132
- """Main script function."""
133
- # Define path to configuration file
134
- config_path = os.path.join(os.path.dirname(__file__), "mcp_proxy_config.json")
135
-
136
- # Analyze configuration
137
- analyze_config(config_path)
138
-
139
-
140
- if __name__ == "__main__":
141
- main()
@@ -1,155 +0,0 @@
1
- """
2
- Example of basic MCPProxyAdapter integration with an existing FastAPI application.
3
- """
4
- import logging
5
- import os
6
- import sys
7
- from typing import Dict, Any, List, Optional
8
-
9
- # Add parent directory to import path
10
- current_dir = os.path.dirname(os.path.abspath(__file__))
11
- parent_dir = os.path.dirname(current_dir)
12
- if parent_dir not in sys.path:
13
- sys.path.insert(0, parent_dir)
14
-
15
- from fastapi import FastAPI, HTTPException, APIRouter
16
- from pydantic import BaseModel
17
- from mcp_proxy_adapter.adapter import MCPProxyAdapter, configure_logger
18
- from mcp_proxy_adapter.registry import CommandRegistry
19
-
20
- # Configure project logging
21
- logging.basicConfig(
22
- level=logging.INFO,
23
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
24
- )
25
-
26
- # Create project logger
27
- project_logger = logging.getLogger("my_project")
28
- project_logger.setLevel(logging.DEBUG)
29
-
30
- # Configure adapter logger using project logger
31
- adapter_logger = configure_logger(project_logger)
32
-
33
- # Create FastAPI application
34
- app = FastAPI(
35
- title="My API with MCP Proxy Integration",
36
- description="API with Command Registry integration, supporting MCP Proxy",
37
- version="1.0.0"
38
- )
39
-
40
- # Define existing endpoints
41
- router = APIRouter()
42
-
43
- class Item(BaseModel):
44
- name: str
45
- price: float
46
- is_active: bool = True
47
-
48
- @router.get("/items", response_model=List[Item])
49
- async def get_items():
50
- """Returns list of items."""
51
- return [
52
- {"name": "Item 1", "price": 10.5, "is_active": True},
53
- {"name": "Item 2", "price": 20.0, "is_active": False},
54
- {"name": "Item 3", "price": 30.0, "is_active": True},
55
- ]
56
-
57
- @router.get("/items/{item_id}", response_model=Item)
58
- async def get_item(item_id: int):
59
- """Returns item information by ID."""
60
- items = [
61
- {"name": "Item 1", "price": 10.5, "is_active": True},
62
- {"name": "Item 2", "price": 20.0, "is_active": False},
63
- {"name": "Item 3", "price": 30.0, "is_active": True},
64
- ]
65
-
66
- if item_id < 1 or item_id > len(items):
67
- raise HTTPException(status_code=404, detail="Item not found")
68
-
69
- return items[item_id - 1]
70
-
71
- # Add existing endpoints to application
72
- app.include_router(router)
73
-
74
- # Define commands for Command Registry
75
- def list_items() -> List[Dict[str, Any]]:
76
- """
77
- Returns list of all items.
78
-
79
- Returns:
80
- List[Dict[str, Any]]: List of items
81
- """
82
- return [
83
- {"name": "Item 1", "price": 10.5, "is_active": True},
84
- {"name": "Item 2", "price": 20.0, "is_active": False},
85
- {"name": "Item 3", "price": 30.0, "is_active": True},
86
- ]
87
-
88
- def get_item_by_id(item_id: int) -> Dict[str, Any]:
89
- """
90
- Returns item information by ID.
91
-
92
- Args:
93
- item_id: Item ID
94
-
95
- Returns:
96
- Dict[str, Any]: Item information
97
-
98
- Raises:
99
- ValueError: If item is not found
100
- """
101
- items = list_items()
102
-
103
- if item_id < 1 or item_id > len(items):
104
- raise ValueError(f"Item with ID {item_id} not found")
105
-
106
- return items[item_id - 1]
107
-
108
- def search_items(query: str, min_price: Optional[float] = None, max_price: Optional[float] = None) -> List[Dict[str, Any]]:
109
- """
110
- Searches for items by name and price range.
111
-
112
- Args:
113
- query: Search query for name
114
- min_price: Minimum price (optional)
115
- max_price: Maximum price (optional)
116
-
117
- Returns:
118
- List[Dict[str, Any]]: List of found items
119
- """
120
- items = list_items()
121
-
122
- # Filter by name
123
- filtered_items = [item for item in items if query.lower() in item["name"].lower()]
124
-
125
- # Filter by minimum price
126
- if min_price is not None:
127
- filtered_items = [item for item in filtered_items if item["price"] >= min_price]
128
-
129
- # Filter by maximum price
130
- if max_price is not None:
131
- filtered_items = [item for item in filtered_items if item["price"] <= max_price]
132
-
133
- return filtered_items
134
-
135
- # Create CommandRegistry instance
136
- registry = CommandRegistry()
137
-
138
- # Register commands
139
- registry.register_command("list_items", list_items)
140
- registry.register_command("get_item", get_item_by_id)
141
- registry.register_command("search_items", search_items)
142
-
143
- # Create MCP Proxy adapter
144
- adapter = MCPProxyAdapter(registry)
145
-
146
- # Register endpoints in existing application
147
- adapter.register_endpoints(app)
148
-
149
- # Save configuration for MCP Proxy
150
- adapter.save_config_to_file("mcp_proxy_config.json")
151
-
152
- # Entry point for running the application
153
- if __name__ == "__main__":
154
- import uvicorn
155
- uvicorn.run(app, host="0.0.0.0", port=8000)
@@ -1,69 +0,0 @@
1
- """
2
- Docstring and Schema Example for MCPProxyAdapter
3
-
4
- - How to write docstrings for commands
5
- - How docstrings are used in OpenAPI/schema
6
- - Best practices for documenting parameters and return values
7
-
8
- Run:
9
- python examples/docstring_and_schema_example.py
10
- """
11
- import os
12
- import sys
13
- import asyncio
14
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
15
- from mcp_proxy_adapter.adapter import MCPProxyAdapter
16
-
17
- class MyRegistry:
18
- def __init__(self):
19
- self.dispatcher = self
20
- self.commands = {"sum": self.sum_numbers}
21
- self.commands_info = {
22
- "sum": {
23
- "description": self.sum_numbers.__doc__,
24
- "params": {
25
- "a": {"type": "integer", "description": "First number", "required": True},
26
- "b": {"type": "integer", "description": "Second number", "required": True}
27
- }
28
- }
29
- }
30
- def get_valid_commands(self):
31
- return list(self.commands.keys())
32
- def get_command_info(self, command):
33
- return self.commands_info.get(command)
34
- def get_commands_info(self):
35
- return self.commands_info
36
- def execute(self, command, **params):
37
- if command == "sum":
38
- return self.sum_numbers(**params)
39
- raise KeyError(f"Unknown command: {command}")
40
- def add_generator(self, generator):
41
- pass
42
- def sum_numbers(self, a: int, b: int) -> int:
43
- """
44
- Returns the sum of two numbers.
45
-
46
- Args:
47
- a (int): First number
48
- b (int): Second number
49
-
50
- Returns:
51
- int: The sum of a and b
52
- """
53
- return a + b
54
-
55
- if __name__ == "__main__":
56
- registry = MyRegistry()
57
- adapter = MCPProxyAdapter(registry)
58
- # Print OpenAPI schema (simulated)
59
- schema = adapter.generate_mcp_proxy_config()
60
- print("=== Tool description from docstring ===")
61
- print(schema.tools[0].description)
62
-
63
- # Call sync handler
64
- result_sync = registry.execute('sum', a=10, b=1)
65
- print(result_sync) # 11
66
-
67
- # Call sync handler (ещё раз)
68
- result_sync2 = registry.execute('sum', a=10, b=10)
69
- print(result_sync2) # 20
@@ -1,72 +0,0 @@
1
- """
2
- Extension Example for MCPProxyAdapter
3
-
4
- - How to add custom commands
5
- - How to extend help logic
6
- - How to customize error handling
7
-
8
- Run:
9
- python examples/extension_example.py
10
- """
11
- import os
12
- import sys
13
- import asyncio
14
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
15
- from mcp_proxy_adapter.adapter import MCPProxyAdapter
16
-
17
- class MyRegistry:
18
- def __init__(self):
19
- self.dispatcher = self
20
- self.commands = {"ping": self.ping, "help": self.help_command}
21
- self.commands_info = {
22
- "ping": {"description": "Ping command (returns pong)", "params": {}},
23
- "help": {"description": "Show help for commands", "params": {"cmdname": {"type": "string", "description": "Command name", "required": False}}}
24
- }
25
- def get_valid_commands(self):
26
- return list(self.commands.keys())
27
- def get_command_info(self, command):
28
- return self.commands_info.get(command)
29
- def get_commands_info(self):
30
- return self.commands_info
31
- def execute(self, *args, **params):
32
- if args:
33
- command = args[0]
34
- params = {k: v for k, v in params.items()}
35
- else:
36
- command = params.pop("cmdname", None)
37
- if command == "ping":
38
- return self.ping()
39
- if command == "help":
40
- return self.help_command(**params)
41
- raise KeyError(f"Unknown command: {command}")
42
- def add_generator(self, generator):
43
- pass
44
- def ping(self):
45
- """Ping command."""
46
- return {"result": "pong"}
47
- def help_command(self, cmdname: str = None):
48
- """Custom help logic: returns info for command or all commands."""
49
- if not cmdname:
50
- return {"commands": list(self.commands_info.keys())}
51
- if cmdname in self.commands_info:
52
- return {"command": cmdname, "info": self.commands_info[cmdname]}
53
- return {"error": f"Command '{cmdname}' not found"}
54
-
55
- if __name__ == "__main__":
56
- registry = MyRegistry()
57
- adapter = MCPProxyAdapter(registry)
58
- # Call sync handler
59
- result_sync = registry.execute("ping")
60
- print(result_sync) # Ping
61
-
62
- # Call help (all)
63
- result_help_all = registry.execute("help")
64
- print("Help (all)", result_help_all)
65
-
66
- # Call help (ping)
67
- result_help_ping = registry.execute("help", cmdname="ping")
68
- print("Help (ping)", result_help_ping)
69
-
70
- # Call help (notfound)
71
- result_help_notfound = registry.execute("help", cmdname="notfound")
72
- print("Help (notfound)", result_help_notfound)
@@ -1,67 +0,0 @@
1
- """
2
- Best Practices: Integrating and Testing 'help' Command in MCPProxyAdapter
3
-
4
- This example demonstrates:
5
- - How to robustly integrate a project-level 'help' command
6
- - How to extend help with custom logic
7
- - How to test help scenarios (including fallback and error cases)
8
- - How to avoid common mistakes
9
-
10
- Run:
11
- python examples/help_best_practices.py
12
- """
13
- import os
14
- import sys
15
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
16
- from typing import Any, Dict
17
- from mcp_proxy_adapter.adapter import MCPProxyAdapter
18
- from mcp_proxy_adapter.testing_utils import MockRegistry
19
-
20
- # --- Setup registry and adapter ---
21
- registry = MockRegistry()
22
- adapter = MCPProxyAdapter(registry)
23
-
24
- def robust_help(cmdname: str = None) -> Dict[str, Any]:
25
- """
26
- Best practice: always check for project help, handle errors, fallback to adapter help.
27
- """
28
- dispatcher = registry.dispatcher
29
- if "help" in dispatcher.get_valid_commands():
30
- try:
31
- if cmdname:
32
- return dispatcher.help_command(cmdname=cmdname)
33
- return dispatcher.help_command()
34
- except Exception as e:
35
- # Log error, fallback to adapter help
36
- print(f"[WARN] Project help failed: {e}. Fallback to adapter help.")
37
- return fallback_adapter_help(cmdname)
38
- else:
39
- return fallback_adapter_help(cmdname)
40
-
41
- def fallback_adapter_help(cmdname: str = None) -> Dict[str, Any]:
42
- """
43
- Fallback: call adapter's help (simulate REST/JSON-RPC call).
44
- """
45
- dispatcher = registry.dispatcher
46
- if not cmdname:
47
- return {"source": "adapter", "commands": dispatcher.get_valid_commands()}
48
- if cmdname in dispatcher.get_valid_commands():
49
- return {"source": "adapter", "command": cmdname, "info": {"description": "Adapter help for command"}}
50
- return {"source": "adapter", "error": f"Command '{cmdname}' not found (adapter)", "available_commands": dispatcher.get_valid_commands()}
51
-
52
- # --- Example test cases ---
53
- def test_help():
54
- """Test all help scenarios."""
55
- print("[TEST] Project help (no param):", robust_help())
56
- print("[TEST] Project help (existing command):", robust_help("success"))
57
- print("[TEST] Project help (nonexistent command, triggers fallback):", robust_help("not_a_command"))
58
- # Simulate registry without help
59
- registry_no_help = MockRegistry()
60
- if "help" in registry_no_help.dispatcher.commands:
61
- del registry_no_help.dispatcher.commands["help"]
62
- global registry
63
- registry = registry_no_help
64
- print("[TEST] Adapter help (no project help present):", robust_help("success"))
65
-
66
- if __name__ == "__main__":
67
- test_help()
@@ -1,64 +0,0 @@
1
- """
2
- Example: Using 'help' command with MCPProxyAdapter
3
-
4
- This script demonstrates how to:
5
- - Call the 'help' command (if present in the project)
6
- - Call 'help' with a parameter (for a specific command)
7
- - Handle errors and fallback to adapter help
8
- - Best practices for integrating and extending help
9
-
10
- Run:
11
- python examples/help_usage.py
12
- """
13
- import os
14
- import sys
15
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
16
- from typing import Any, Dict
17
-
18
- # Assume MCPProxyAdapter and MockRegistry are available from src and tests
19
- from mcp_proxy_adapter.adapter import MCPProxyAdapter
20
- from mcp_proxy_adapter.testing_utils import MockRegistry
21
-
22
- # --- Setup registry and adapter ---
23
- registry = MockRegistry()
24
- adapter = MCPProxyAdapter(registry)
25
-
26
- # --- Best practice: always check if 'help' is in commands ---
27
- def call_help(cmdname: str = None) -> Dict[str, Any]:
28
- """Call help command with or without parameter."""
29
- dispatcher = registry.dispatcher
30
- if "help" in dispatcher.get_valid_commands():
31
- if cmdname:
32
- try:
33
- return dispatcher.help_command(cmdname=cmdname)
34
- except Exception as e:
35
- print(f"Project help failed: {e}. Fallback to adapter help.")
36
- return adapter_help(cmdname)
37
- else:
38
- return dispatcher.help_command()
39
- else:
40
- return adapter_help(cmdname)
41
-
42
- def adapter_help(cmdname: str = None) -> Dict[str, Any]:
43
- """Fallback: call adapter's help (simulate)."""
44
- dispatcher = registry.dispatcher
45
- if not cmdname:
46
- return {"source": "adapter", "commands": dispatcher.get_valid_commands()}
47
- if cmdname in dispatcher.get_valid_commands():
48
- return {"source": "adapter", "command": 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
-
51
- if __name__ == "__main__":
52
- print("=== Project help (no param) ===")
53
- print(call_help())
54
- print("\n=== Project help (existing command) ===")
55
- print(call_help("success"))
56
- print("\n=== Project help (nonexistent command, triggers fallback) ===")
57
- print(call_help("not_a_command"))
58
- print("\n=== Adapter help (no project help present) ===")
59
- # Simulate registry without help
60
- registry_no_help = MockRegistry()
61
- if "help" in registry_no_help.dispatcher.commands:
62
- del registry_no_help.dispatcher.commands["help"]
63
- adapter_no_help = MCPProxyAdapter(registry_no_help)
64
- print(adapter_help("success"))