Skip to main content
Glama
senseisven

MCP Remote macOS Control Server

by senseisven

remote_macos_send_keys

Send keyboard input to remote macOS systems for automated control, including text entry, special keys, and key combinations via VNC connection.

Instructions

Send keyboard input to a remote MacOs machine. Uses environment variables for connection details.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
textNoText to send as keystrokes
special_keyNoSpecial key to send (e.g., 'enter', 'backspace', 'tab', 'escape', etc.)
key_combinationNoKey combination to send (e.g., 'ctrl+c', 'cmd+q', 'ctrl+alt+delete', etc.)

Implementation Reference

  • Main execution logic for the remote_macos_send_keys tool. Connects to VNC, handles text input, special keys, and key combinations using VNCClient methods.
    def handle_remote_macos_send_keys(arguments: dict[str, Any]) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
        """Send keyboard input to a remote MacOs machine."""
        # Use environment variables
        host = MACOS_HOST
        port = MACOS_PORT
        password = MACOS_PASSWORD
        username = MACOS_USERNAME
        encryption = VNC_ENCRYPTION
    
        # Get required parameters from arguments
        text = arguments.get("text")
        special_key = arguments.get("special_key")
        key_combination = arguments.get("key_combination")
    
        if not text and not special_key and not key_combination:
            raise ValueError("Either text, special_key, or key_combination must be provided")
    
        # Initialize VNC client
        vnc = VNCClient(host=host, port=port, password=password, username=username, encryption=encryption)
    
        # Connect to remote MacOs machine
        success, error_message = vnc.connect()
        if not success:
            error_msg = f"Failed to connect to remote MacOs machine at {host}:{port}. {error_message}"
            return [types.TextContent(type="text", text=error_msg)]
    
        try:
            result_message = []
    
            # Map of special key names to X11 keysyms
            special_keys = {
                "enter": 0xff0d,
                "return": 0xff0d,
                "backspace": 0xff08,
                "tab": 0xff09,
                "escape": 0xff1b,
                "esc": 0xff1b,
                "delete": 0xffff,
                "del": 0xffff,
                "home": 0xff50,
                "end": 0xff57,
                "page_up": 0xff55,
                "page_down": 0xff56,
                "left": 0xff51,
                "up": 0xff52,
                "right": 0xff53,
                "down": 0xff54,
                "f1": 0xffbe,
                "f2": 0xffbf,
                "f3": 0xffc0,
                "f4": 0xffc1,
                "f5": 0xffc2,
                "f6": 0xffc3,
                "f7": 0xffc4,
                "f8": 0xffc5,
                "f9": 0xffc6,
                "f10": 0xffc7,
                "f11": 0xffc8,
                "f12": 0xffc9,
                "space": 0x20,
            }
    
            # Map of modifier key names to X11 keysyms
            modifier_keys = {
                "ctrl": 0xffe3,    # Control_L
                "control": 0xffe3,  # Control_L
                "shift": 0xffe1,   # Shift_L
                "alt": 0xffe9,     # Alt_L
                "option": 0xffe9,  # Alt_L (Mac convention)
                "cmd": 0xffeb,     # Command_L (Mac convention)
                "command": 0xffeb,  # Command_L (Mac convention)
                "win": 0xffeb,     # Command_L
                "super": 0xffeb,   # Command_L
                "fn": 0xffed,      # Function key
                "meta": 0xffeb,    # Command_L (Mac convention)
            }
    
            # Map for letter keys (a-z)
            letter_keys = {chr(i): i for i in range(ord('a'), ord('z') + 1)}
    
            # Map for number keys (0-9)
            number_keys = {str(i): ord(str(i)) for i in range(10)}
    
            # Process special key
            if special_key:
                if special_key.lower() in special_keys:
                    key = special_keys[special_key.lower()]
                    if vnc.send_key_event(key, True) and vnc.send_key_event(key, False):
                        result_message.append(f"Sent special key: {special_key}")
                    else:
                        result_message.append(f"Failed to send special key: {special_key}")
                else:
                    result_message.append(f"Unknown special key: {special_key}")
                    result_message.append(f"Supported special keys: {', '.join(special_keys.keys())}")
    
            # Process text
            if text:
                if vnc.send_text(text):
                    result_message.append(f"Sent text: '{text}'")
                else:
                    result_message.append(f"Failed to send text: '{text}'")
    
            # Process key combination
            if key_combination:
                keys = []
                for part in key_combination.lower().split('+'):
                    part = part.strip()
                    if part in modifier_keys:
                        keys.append(modifier_keys[part])
                    elif part in special_keys:
                        keys.append(special_keys[part])
                    elif part in letter_keys:
                        keys.append(letter_keys[part])
                    elif part in number_keys:
                        keys.append(number_keys[part])
                    elif len(part) == 1:
                        # For any other single character keys
                        keys.append(ord(part))
                    else:
                        result_message.append(f"Unknown key in combination: {part}")
                        break
    
                if len(keys) == len(key_combination.split('+')):
                    if vnc.send_key_combination(keys):
                        result_message.append(f"Sent key combination: {key_combination}")
                    else:
                        result_message.append(f"Failed to send key combination: {key_combination}")
    
            return [types.TextContent(type="text", text="\n".join(result_message))]
        finally:
            vnc.close()
  • Input schema definition for the remote_macos_send_keys tool, specifying properties for text, special_key, and key_combination.
        name="remote_macos_send_keys",
        description="Send keyboard input to a remote MacOs machine. Uses environment variables for connection details.",
        inputSchema={
            "type": "object",
            "properties": {
                "text": {"type": "string", "description": "Text to send as keystrokes"},
                "special_key": {"type": "string", "description": "Special key to send (e.g., 'enter', 'backspace', 'tab', 'escape', etc.)"},
                "key_combination": {"type": "string", "description": "Key combination to send (e.g., 'ctrl+c', 'cmd+q', 'ctrl+alt+delete', etc.)"}
            },
            "required": []
        },
    ),
  • Tool dispatch registration in the MCP server's call_tool handler, mapping 'remote_macos_send_keys' to the action handler function.
    elif name == "remote_macos_send_keys":
        return handle_remote_macos_send_keys(arguments)
  • Import of the handler function for use in tool registration.
    handle_remote_macos_send_keys,

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/senseisven/mcp_macos'

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