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 and task execution. Use text, special keys, or key combinations to interact with applications and perform actions.

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

  • The core handler function that connects to the remote MacOS via VNC and implements sending text keystrokes, special keys (e.g., enter, tab), or key combinations (e.g., cmd+c) using VNCClient methods like send_text, send_key_event, and send_key_combination.
    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()
  • Registers the tool in the MCP server's list_tools() method, including name, description, and input schema definition.
    types.Tool( 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": [] }, ),
  • In the MCP server's call_tool() handler, dispatches execution to the handle_remote_macos_send_keys function.
    elif name == "remote_macos_send_keys": return handle_remote_macos_send_keys(arguments)
  • Defines the JSON schema for tool inputs: text, special_key, or key_combination.
    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": [] }, ),

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