From 89ff9609fbbec6d5f241bd79818a82fc8d2f4857 Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Thu, 14 Aug 2025 08:27:12 -0600 Subject: [PATCH] Simplify adb_input with string coordinates to fix MCP validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Changed all coordinate parameters to string type with empty defaults - Simplified parameter validation using string checks - Updated documentation to show string coordinates - Removed complex optional parameter combinations causing MCP issues 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/server.py | 76 ++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/src/server.py b/src/server.py index c5995dc..9808b2f 100644 --- a/src/server.py +++ b/src/server.py @@ -41,28 +41,6 @@ class ADBCommand(BaseModel): device_id: Optional[str] = None -class InputAction(BaseModel): - """Input action parameters for simulating user interactions""" - action_type: str = Field( - description="Type of input action to perform", - json_schema_extra={ - "enum": ["tap", "swipe", "key", "text"], - "examples": ["tap", "swipe", "key", "text"] - } - ) - x: Optional[int] = Field(None, description="X coordinate for tap/swipe start (pixels)", ge=0) - y: Optional[int] = Field(None, description="Y coordinate for tap/swipe start (pixels)", ge=0) - x2: Optional[int] = Field(None, description="X coordinate for swipe end (pixels)", ge=0) - y2: Optional[int] = Field(None, description="Y coordinate for swipe end (pixels)", ge=0) - key_code: Optional[str] = Field( - None, - description="Android key code (e.g., KEYCODE_BACK, KEYCODE_HOME, KEYCODE_CAMERA)", - json_schema_extra={ - "examples": ["KEYCODE_BACK", "KEYCODE_HOME", "KEYCODE_CAMERA", "KEYCODE_VOLUME_DOWN"] - } - ) - text: Optional[str] = Field(None, description="Text to type (for text action type)") - # Initialize FastMCP server mcp = FastMCP("android-mcp-server") @@ -172,48 +150,60 @@ async def adb_screenshot( @mcp.tool() async def adb_input( - action: InputAction = Field(description="Input action to perform on the device"), - device_id: Optional[str] = Field(None, description="Target device ID (if multiple devices connected)") + action_type: str, + x: str = "", + y: str = "", + x2: str = "", + y2: str = "", + key_code: str = "", + text: str = "", + device_id: Optional[str] = None ) -> Dict[str, Any]: """ Send input events to Android device to simulate user interactions. - Supports various input types: - - tap: Single touch at coordinates (requires x, y) - - swipe: Drag gesture from one point to another (requires x, y, x2, y2) - - key: Hardware key press (requires key_code like KEYCODE_BACK) - - text: Type text input (requires text string) + Supports various input types with simple parameter interface: + - tap: adb_input(action_type="tap", x="400", y="600") + - swipe: adb_input(action_type="swipe", x="100", y="200", x2="300", y2="400") + - key: adb_input(action_type="key", key_code="KEYCODE_BACK") + - text: adb_input(action_type="text", text="Hello World") Args: - action: Input action configuration with type and parameters + action_type: Type of input action ("tap", "swipe", "key", "text") + x: X coordinate for tap/swipe start (required for tap/swipe) + y: Y coordinate for tap/swipe start (required for tap/swipe) + x2: X coordinate for swipe end (required for swipe) + y2: Y coordinate for swipe end (required for swipe) + key_code: Android key code like KEYCODE_BACK (required for key) + text: Text to type (required for text) device_id: Specific device to target (optional if only one device) Returns: Command execution result with success status """ - if action.action_type == "tap": - if action.x is None or action.y is None: + if action_type == "tap": + if not x or not y: raise ValueError("tap action requires x and y coordinates") - cmd = ["shell", "input", "tap", str(action.x), str(action.y)] + cmd = ["shell", "input", "tap", x, y] - elif action.action_type == "swipe": - if any(coord is None for coord in [action.x, action.y, action.x2, action.y2]): + elif action_type == "swipe": + if not x or not y or not x2 or not y2: raise ValueError("swipe action requires x, y, x2, y2 coordinates") - cmd = ["shell", "input", "swipe", str(action.x), str(action.y), str(action.x2), str(action.y2)] + cmd = ["shell", "input", "swipe", x, y, x2, y2] - elif action.action_type == "key": - if action.key_code is None: + elif action_type == "key": + if not key_code: raise ValueError("key action requires key_code") - cmd = ["shell", "input", "keyevent", action.key_code] + cmd = ["shell", "input", "keyevent", key_code] - elif action.action_type == "text": - if action.text is None: + elif action_type == "text": + if not text: raise ValueError("text action requires text") - cmd = ["shell", "input", "text", action.text] + cmd = ["shell", "input", "text", text] else: - raise ValueError(f"Unknown action type: {action.action_type}") + raise ValueError(f"Unknown action type: {action_type}. Must be one of: tap, swipe, key, text") result = await run_adb_command(cmd, device_id) return result