From 5ae32c91e59780667e4cc2d550d165cc824b0c21 Mon Sep 17 00:00:00 2001 From: gantnocap Date: Tue, 11 Mar 2025 13:09:49 +0800 Subject: [PATCH] update format --- openmanus_server/README.md | 4 +- openmanus_server/mcp_requirements.txt | 2 +- openmanus_server/openmanus_client_example.py | 75 +++++++++++--------- openmanus_server/openmanus_server.py | 61 +++++++++------- 4 files changed, 80 insertions(+), 62 deletions(-) diff --git a/openmanus_server/README.md b/openmanus_server/README.md index 49eb5c7..6992f21 100644 --- a/openmanus_server/README.md +++ b/openmanus_server/README.md @@ -16,7 +16,7 @@ This MCP server provides access to the following OpenManus tools: ### Prerequisites -- Python 3.10+ +- Python 3.10+ - OpenManus project dependencies ### Installation Steps @@ -127,4 +127,4 @@ uv run openmanus_server/openmanus_client_example.py openmanus_server/openmanus_s ## 📄 License -Same license as the OpenManus project \ No newline at end of file +Same license as the OpenManus project diff --git a/openmanus_server/mcp_requirements.txt b/openmanus_server/mcp_requirements.txt index c9b19fc..cba6c36 100644 --- a/openmanus_server/mcp_requirements.txt +++ b/openmanus_server/mcp_requirements.txt @@ -1,3 +1,3 @@ # Core dependencies mcp -httpx>=0.27.0 \ No newline at end of file +httpx>=0.27.0 diff --git a/openmanus_server/openmanus_client_example.py b/openmanus_server/openmanus_client_example.py index 4287b4e..3b8e8aa 100644 --- a/openmanus_server/openmanus_client_example.py +++ b/openmanus_server/openmanus_client_example.py @@ -1,11 +1,12 @@ import asyncio -from typing import Optional -from contextlib import AsyncExitStack import os +from contextlib import AsyncExitStack +from typing import Optional from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client + class OpenManusClient: def __init__(self): # Initialize session and client objects @@ -20,7 +21,7 @@ class OpenManusClient: Args: server_script_path: Path to the server script """ - if not server_script_path.endswith('.py'): + if not server_script_path.endswith(".py"): raise ValueError("Server script must be a .py file") # Get the current directory to add to PYTHONPATH @@ -29,23 +30,29 @@ class OpenManusClient: # Prepare environment variables env = os.environ.copy() # Copy current environment - + # Add current directory and project root to PYTHONPATH - path_separator = ';' if os.name == 'nt' else ':' # Use ; for Windows, : for Unix - if 'PYTHONPATH' in env: - env['PYTHONPATH'] = f"{current_dir}{path_separator}{project_root}{path_separator}{env['PYTHONPATH']}" + path_separator = ( + ";" if os.name == "nt" else ":" + ) # Use ; for Windows, : for Unix + if "PYTHONPATH" in env: + env[ + "PYTHONPATH" + ] = f"{current_dir}{path_separator}{project_root}{path_separator}{env['PYTHONPATH']}" else: - env['PYTHONPATH'] = f"{current_dir}{path_separator}{project_root}" + env["PYTHONPATH"] = f"{current_dir}{path_separator}{project_root}" server_params = StdioServerParameters( - command="python", - args=[server_script_path], - env=env + command="python", args=[server_script_path], env=env ) - stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params)) + stdio_transport = await self.exit_stack.enter_async_context( + stdio_client(server_params) + ) self.stdio, self.write = stdio_transport - self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write)) + self.session = await self.exit_stack.enter_async_context( + ClientSession(self.stdio, self.write) + ) await self.session.initialize() # List available tools @@ -59,8 +66,7 @@ class OpenManusClient: try: print("\nExample 1: Google Search") search_result = await self.session.call_tool( - "google_search", - {"query": "Model Context Protocol", "num_results": 5} + "google_search", {"query": "Model Context Protocol", "num_results": 5} ) print(f"Search results: {search_result.content}") @@ -73,8 +79,7 @@ for i in range(1, 10): print(f"Calculation result: {result}") """ python_result = await self.session.call_tool( - "python_execute", - {"code": code, "timeout": 3} + "python_execute", {"code": code, "timeout": 3} ) print(f"Python execution result: {python_result.content}") @@ -83,24 +88,20 @@ print(f"Calculation result: {result}") "file_saver", { "content": "This is a test file content saved through MCP", - "file_path": "mcp_test_file.txt" - } + "file_path": "mcp_test_file.txt", + }, ) print(f"File save result: {file_result.content}") print("\nExample 4: Browser Usage") # Navigate to webpage browser_result = await self.session.call_tool( - "browser_use", - {"action": "navigate", "url": "https://www.example.com"} + "browser_use", {"action": "navigate", "url": "https://www.example.com"} ) print(f"Browser navigation result: {browser_result.content}") # Get browser state - state_result = await self.session.call_tool( - "get_browser_state", - {} - ) + state_result = await self.session.call_tool("get_browser_state", {}) print(f"Browser state: {state_result.content}") except Exception as e: @@ -110,13 +111,15 @@ print(f"Calculation result: {result}") """Run an interactive chat loop for testing tools""" print("\nOpenManus MCP Client Started!") print("Type your commands or 'quit' to exit.") - print("Available commands: google_search, python_execute, file_saver, browser_use, get_browser_state") + print( + "Available commands: google_search, python_execute, file_saver, browser_use, get_browser_state" + ) while True: try: command = input("\nCommand: ").strip() - if command.lower() == 'quit': + if command.lower() == "quit": break # Parse command and parameters @@ -130,7 +133,9 @@ print(f"Calculation result: {result}") try: tool_args = eval(parts[1]) # Convert string to dict except: - print("Invalid arguments format. Please provide a valid Python dictionary.") + print( + "Invalid arguments format. Please provide a valid Python dictionary." + ) continue result = await self.session.call_tool(tool_name, tool_args) @@ -146,29 +151,31 @@ print(f"Calculation result: {result}") await self.exit_stack.aclose() print("\nClosed MCP client connection") + async def main(): """Main entry point""" import sys - + if len(sys.argv) < 2: print("Usage: python openmanus_client_example.py ") print("Example: python openmanus_client_example.py ../mcp_server.py") sys.exit(1) - + client = OpenManusClient() try: await client.connect_to_server(server_script_path=sys.argv[1]) - + # Run examples first await client.run_examples() - + # Then start interactive chat loop await client.chat_loop() - + except Exception as e: print(f"Error: {str(e)}") finally: await client.cleanup() + if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file + asyncio.run(main()) diff --git a/openmanus_server/openmanus_server.py b/openmanus_server/openmanus_server.py index d25f9a6..d73add4 100644 --- a/openmanus_server/openmanus_server.py +++ b/openmanus_server/openmanus_server.py @@ -1,11 +1,13 @@ -from typing import Optional +import argparse import asyncio import json -import argparse -from mcp.server.fastmcp import FastMCP import logging import os import sys +from typing import Optional + +from mcp.server.fastmcp import FastMCP + # Add current directory to Python path current_dir = os.path.dirname(os.path.abspath(__file__)) @@ -15,18 +17,18 @@ sys.path.insert(0, current_dir) # Configure logging logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' + level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger("mcp-server") # Import OpenManus tools from app.tool.browser_use_tool import BrowserUseTool +from app.tool.file_saver import FileSaver from app.tool.google_search import GoogleSearch from app.tool.python_execute import PythonExecute -from app.tool.file_saver import FileSaver from app.tool.terminate import Terminate + # Initialize FastMCP server openmanus = FastMCP("openmanus") @@ -37,6 +39,7 @@ python_execute_tool = PythonExecute() file_saver_tool = FileSaver() terminate_tool = Terminate() + # Browser tool @openmanus.tool() async def browser_use( @@ -49,7 +52,7 @@ async def browser_use( tab_id: Optional[int] = None, ) -> str: """Execute various browser operations. - + Args: action: The browser operation to execute, possible values include: - navigate: Navigate to specified URL @@ -79,10 +82,11 @@ async def browser_use( text=text, script=script, scroll_amount=scroll_amount, - tab_id=tab_id + tab_id=tab_id, ) return json.dumps(result.model_dump()) + @openmanus.tool() async def get_browser_state() -> str: """Get current browser state, including URL, title, tabs and interactive elements.""" @@ -90,11 +94,12 @@ async def get_browser_state() -> str: result = await browser_tool.get_current_state() return json.dumps(result.model_dump()) + # Google search tool @openmanus.tool() async def google_search(query: str, num_results: int = 10) -> str: """Execute Google search and return list of relevant links. - + Args: query: Search query num_results: Number of results to return (default is 10) @@ -103,11 +108,12 @@ async def google_search(query: str, num_results: int = 10) -> str: results = await google_search_tool.execute(query=query, num_results=num_results) return json.dumps(results) + # Python execution tool @openmanus.tool() async def python_execute(code: str, timeout: int = 5) -> str: """Execute Python code and return results. - + Args: code: Python code to execute timeout: Execution timeout in seconds @@ -116,25 +122,29 @@ async def python_execute(code: str, timeout: int = 5) -> str: result = await python_execute_tool.execute(code=code, timeout=timeout) return json.dumps(result) + # File saver tool @openmanus.tool() async def file_saver(content: str, file_path: str, mode: str = "w") -> str: """Save content to local file. - + Args: content: Content to save file_path: File path mode: File open mode (default is 'w') """ logger.info(f"Saving file: {file_path}") - result = await file_saver_tool.execute(content=content, file_path=file_path, mode=mode) + result = await file_saver_tool.execute( + content=content, file_path=file_path, mode=mode + ) return result + # Terminate tool @openmanus.tool() async def terminate(status: str) -> str: """Terminate program execution. - + Args: status: Termination status, can be 'success' or 'failure' """ @@ -142,44 +152,45 @@ async def terminate(status: str) -> str: result = await terminate_tool.execute(status=status) return result + # Clean up resources async def cleanup(): """Clean up all tool resources""" logger.info("Cleaning up resources") await browser_tool.cleanup() + # Register cleanup function import atexit + + atexit.register(lambda: asyncio.run(cleanup())) + def parse_args(): """Parse command line arguments""" parser = argparse.ArgumentParser(description="OpenManus MCP Server") parser.add_argument( - "--transport", - choices=["stdio", "http"], + "--transport", + choices=["stdio", "http"], default="stdio", - help="Communication method: stdio or http (default: stdio)" + help="Communication method: stdio or http (default: stdio)", ) parser.add_argument( - "--host", - default="127.0.0.1", - help="HTTP server host (default: 127.0.0.1)" + "--host", default="127.0.0.1", help="HTTP server host (default: 127.0.0.1)" ) parser.add_argument( - "--port", - type=int, - default=8000, - help="HTTP server port (default: 8000)" + "--port", type=int, default=8000, help="HTTP server port (default: 8000)" ) return parser.parse_args() + if __name__ == "__main__": args = parse_args() - + if args.transport == "stdio": logger.info("Starting OpenManus server (stdio mode)") openmanus.run(transport="stdio") else: logger.info(f"Starting OpenManus server (HTTP mode) at {args.host}:{args.port}") - openmanus.run(transport="http", host=args.host, port=args.port) \ No newline at end of file + openmanus.run(transport="http", host=args.host, port=args.port)