Skip to main content
Glama

android-device

List, connect, disconnect, reboot Android devices and retrieve their properties.

Instructions

Perform various device management operations on Android devices.

This single tool consolidates various device-related actions. The 'action' parameter determines the operation.

Args: action: The specific device operation to perform. ctx: MCP Context for logging and interaction. serial (Optional[str]): Device serial number. Required by most actions except connect/list. ip_address (Optional[str]): IP address for 'connect_device' action. port (Optional[int]): Port for 'connect_device' action (default: 5555). mode (Optional[str]): Reboot mode for 'reboot_device' action (default: "normal").

Returns: A string message indicating the result or status of the operation.


Available Actions and their specific argument usage:

  1. action="list_devices"

    • No specific arguments required beyond ctx.

  2. action="connect_device"

    • Requires: ip_address

    • Optional: port

  3. action="disconnect_device"

    • Requires: serial

  4. action="reboot_device"

    • Requires: serial

    • Optional: mode (e.g., "normal", "recovery", "bootloader")

  5. action="device_properties"

    • Requires: serial


Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYes
serialNo
ip_addressNo
portNo
modeNonormal

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The main handler function for the 'android-device' MCP tool. Decorated with @mcp.tool(name='android-device'). Dispatches to sub-actions (list_devices, connect_device, disconnect_device, reboot_device, device_properties) based on the DeviceAction enum.
    @mcp.tool(name="android-device")
    async def android_device(
        action: DeviceAction,
        ctx: Context,
        serial: str | None = None,
        ip_address: str | None = None,
        port: int = 5555,
        mode: str = "normal",
    ) -> str:
        """
        Perform various device management operations on Android devices.
    
        This single tool consolidates various device-related actions.
        The 'action' parameter determines the operation.
    
        Args:
            action: The specific device operation to perform.
            ctx: MCP Context for logging and interaction.
            serial (Optional[str]): Device serial number. Required by most actions except connect/list.
            ip_address (Optional[str]): IP address for 'connect_device' action.
            port (Optional[int]): Port for 'connect_device' action (default: 5555).
            mode (Optional[str]): Reboot mode for 'reboot_device' action (default: "normal").
    
        Returns:
            A string message indicating the result or status of the operation.
    
        ---
        Available Actions and their specific argument usage:
    
        1.  `action="list_devices"`
            - No specific arguments required beyond `ctx`.
        2.  `action="connect_device"`
            - Requires: `ip_address`
            - Optional: `port`
        3.  `action="disconnect_device"`
            - Requires: `serial`
        4.  `action="reboot_device"`
            - Requires: `serial`
            - Optional: `mode` (e.g., "normal", "recovery", "bootloader")
        5.  `action="device_properties"`
            - Requires: `serial`
        ---
        """
        try:
            # Argument checks based on action
            if (
                action
                in [
                    DeviceAction.DISCONNECT_DEVICE,
                    DeviceAction.REBOOT_DEVICE,
                    DeviceAction.DEVICE_PROPERTIES,
                ]
                and serial is None
            ):
                return f"❌ Error: 'serial' is required for action '{action.value}'."
    
            if action == DeviceAction.CONNECT_DEVICE and ip_address is None:
                return "❌ Error: 'ip_address' is required for action 'connect_device'."
    
            # Dispatch to implementations
            if action == DeviceAction.LIST_DEVICES:
                return await _list_devices_impl(ctx)
            if action == DeviceAction.CONNECT_DEVICE:
                # ip_address is checked not None above
                return await _connect_device_impl(ctx, ip_address, port)  # type: ignore
            if action == DeviceAction.DISCONNECT_DEVICE:
                return await _disconnect_device_impl(serial, ctx)  # type: ignore
            if action == DeviceAction.REBOOT_DEVICE:
                return await _reboot_device_impl(serial, ctx, mode)  # type: ignore
            if action == DeviceAction.DEVICE_PROPERTIES:
                return await _device_properties_impl(serial, ctx)  # type: ignore
    
            # Should not be reached if DeviceAction enum is comprehensive
            valid_actions = ", ".join([act.value for act in DeviceAction])
            logger.error("Invalid device action '%s' received. Valid actions are: %s", action, valid_actions)
            return f"❌ Error: Unknown device action '{action}'. Valid actions are: {valid_actions}."
    
        except Exception as e:
            logger.exception("Unexpected error during device operation %s for serial '%s': %s", action, serial, e)
            return f"❌ Error: An unexpected error occurred during '{action.value}': {e!s}"
  • DeviceAction enum that defines all valid sub-actions for the android-device tool: list_devices, connect_device, disconnect_device, reboot_device, device_properties.
    class DeviceAction(str, Enum):
        """Defines the available sub-actions for the 'android-device' tool."""
    
        LIST_DEVICES = "list_devices"
        CONNECT_DEVICE = "connect_device"
        DISCONNECT_DEVICE = "disconnect_device"
        REBOOT_DEVICE = "reboot_device"
        DEVICE_PROPERTIES = "device_properties"
  • Tool registration via the @mcp.tool(name='android-device') decorator on the FastMCP instance created in droidmind/context.py.
    @mcp.tool(name="android-device")
  • Package __init__.py that imports and re-exports the android_device function, making it available when the tools package is loaded.
    """
    DroidMind Tools Package - MCP tools for controlling Android devices.
    
    This package provides MCP tools for controlling Android devices via ADB.
    Tools are organized by functionality into separate modules.
    """
    
    import logging
    
    from droidmind.devices import get_device_manager
    from droidmind.tools.app_management import (
        app_operations,
    )
    
    # Re-export all tool functions for backward compatibility
    from droidmind.tools.device_management import (
        android_device,
    )
    from droidmind.tools.diagnostics import (
        android_diag,
    )
    from droidmind.tools.file_operations import file_operations
    from droidmind.tools.logs import (
        android_log,
    )
    from droidmind.tools.media import (
        screenshot,
    )
    from droidmind.tools.shell import (
        shell_command,
    )
    from droidmind.tools.ui import (
        android_ui,
    )
    
    # Re-export get_device_manager for backward compatibility
    __all__ = [
        "android_device",
        "android_diag",
        "android_log",
        "android_ui",
        "app_operations",
        "file_operations",
        "get_device_manager",
        "screenshot",
        "shell_command",
    ]
  • Helper implementation for the list_devices sub-action. Lists all connected Android devices via the DeviceManager.
    async def _list_devices_impl(ctx: Context) -> str:
        """
        List all connected Android devices.
    
        Returns:
            A formatted list of connected devices with their basic information.
        """
        try:
            devices = await get_device_manager().list_devices()
    
            if not devices:
                return "No devices connected. Use the connect_device tool to connect to a device."
    
            # Format the device information
            result = f"# Connected Android Devices ({len(devices)})\n\n"
    
            for i, device in enumerate(devices, 1):
                model = await device.model
                android_version = await device.android_version
                result += f"""## Device {i}: {model}
    - **Serial**: `{device.serial}`
    - **Android Version**: {android_version}
    """
    
            return result
        except Exception as e:
            logger.exception("Error in list_devices_impl: %s", e)
            return f"❌ Error listing devices: {e}\n\nCheck logs for detailed traceback."
  • Helper implementation for the connect_device sub-action. Connects to a device over TCP/IP with IP validation.
    async def _connect_device_impl(ctx: Context, ip_address: str, port: int = 5555) -> str:
        """
        Connect to an Android device over TCP/IP.
    
        Args:
            ip_address: The IP address of the device to connect to
            port: The port to connect to (default: 5555)
    
        Returns:
            A message indicating success or failure
        """
        # Validate IP address format
        ip_pattern = r"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$"
        if not re.match(ip_pattern, ip_address):
            return "❌ Invalid IP address format. Please use the format: xxx.xxx.xxx.xxx"
    
        # Validate port range
        if port < 1 or port > 65535:
            return "❌ Invalid port number. Port must be between 1 and 65535."
    
        try:
            # Attempt to connect to the device
            device = await get_device_manager().connect(ip_address, port)
    
            if device:
                model = await device.model
                android_version = await device.android_version
    
                return f"""
    # ✨ Device Connected Successfully! ✨
    
    - **Device**: {model}
    - **Connection**: {ip_address}:{port}
    - **Android Version**: {android_version}
    
    The device is now available for commands and operations.
                """
    
            return f"❌ Failed to connect to device at {ip_address}:{port}"
        except Exception as e:
            logger.exception("Error connecting to device in _connect_device_impl: %s", e)
            return f"❌ Error connecting to device: {e!s}"
  • Helper implementation for the disconnect_device sub-action. Disconnects from a device by serial.
    async def _disconnect_device_impl(serial: str, ctx: Context) -> str:
        """
        Disconnect from an Android device.
    
        Args:
            serial: Device serial number
    
        Returns:
            Disconnection result message
        """
        try:
            await ctx.info(f"Disconnecting from device {serial}...")
            success = await get_device_manager().disconnect(serial)
    
            if success:
                return f"Successfully disconnected from device {serial}"
    
            return f"Device {serial} was not connected"
        except Exception as e:
            logger.exception("Error disconnecting from device in _disconnect_device_impl: %s", e)
            return f"Error disconnecting from device: {e!s}"
  • Helper implementation for the reboot_device sub-action. Reboots a device in normal, recovery, or bootloader mode.
    async def _reboot_device_impl(serial: str, ctx: Context, mode: str = "normal") -> str:
        """
        Reboot the device.
    
        Args:
            serial: Device serial number
            mode: Reboot mode - "normal", "recovery", or "bootloader"
    
        Returns:
            Reboot result message
        """
        valid_modes = ["normal", "recovery", "bootloader"]
        if mode not in valid_modes:
            return f"Invalid reboot mode: {mode}. Must be one of: {', '.join(valid_modes)}"
    
        try:
            device = await get_device_manager().get_device(serial)
    
            if not device:
                return f"Error: Device {serial} not connected or not found."
    
            # Reboot the device
            await ctx.info(f"Rebooting device {serial} in {mode} mode...")
            await device.reboot(mode)
    
            return f"Device {serial} is rebooting in {mode} mode"
        except Exception as e:
            logger.exception("Error rebooting device in _reboot_device_impl: %s", e)
            return f"Error rebooting device: {e!s}"
  • Helper implementation for the device_properties sub-action. Retrieves and formats detailed device properties.
    async def _device_properties_impl(serial: str, ctx: Context) -> str:
        """
        Get detailed properties of a specific device.
    
        Args:
            serial: Device serial number
    
        Returns:
            Formatted device properties as text
        """
        try:
            device = await get_device_manager().get_device(serial)
    
            if not device:
                return f"Device {serial} not found or not connected."
    
            properties = await device.get_properties()
    
            # Format the properties
            result = f"# Device Properties for {serial}\n\n"
    
            # Add formatted sections for important properties
            model = await device.model
            brand = await device.brand
            android_version = await device.android_version
            sdk_level = await device.sdk_level
            build_number = await device.build_number
    
            result += f"**Model**: {model}\n"
            result += f"**Brand**: {brand}\n"
            result += f"**Android Version**: {android_version}\n"
            result += f"**SDK Level**: {sdk_level}\n"
            result += f"**Build Number**: {build_number}\n\n"
    
            # Add all properties in a code block
            result += "## All Properties\n\n```properties\n"
    
            # Sort properties for consistent output
            for key in sorted(properties.keys()):
                value = properties[key]
                result += f"{key}={value}\n"
    
            result += "```"
            return result
        except Exception as e:
            logger.exception("Error retrieving device properties in _device_properties_impl: %s", e)
            return f"Error retrieving device properties: {e!s}"
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full behavioral burden. It details each action's required and optional parameters and notes return type. However, it lacks disclosure of side effects (e.g., reboot disconnects device) and error cases. Still, it is fairly transparent, earning a 4.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a brief intro, standard arg list, and a clear enumeration of actions with their specific arguments. Every sentence adds value; no fluff. Score 5 for efficient organization.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 5 parameters, 5 actions, and no annotations, the description covers action-parameter dependencies and return type. It lacks error handling or examples, but is otherwise complete for a moderately complex tool. Score 4.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It effectively maps parameters to actions, clarifying which parameters are needed for which operation. This adds significant meaning beyond the schema, though detailed constraints (e.g., valid formats) are omitted. Score 4.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states it performs device management operations and lists actions via an enum. While it does not explicitly differentiate from sibling tools like android-shell or android-diag, the action list provides clarity on scope. A score of 4 reflects clear purpose with minor sibling differentiation gap.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by enumerating actions but does not provide explicit when-to-use or when-not-to-use guidance compared to siblings. No alternatives or exclusions are mentioned. Score 3 for implied but unguided usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hyperb1iss/droidmind'

If you have feedback or need assistance with the MCP directory API, please join our Discord server