{
  "serverInfo": {
    "name": "Icemoon",
    "title": "Icemoon — control a real iPhone with AI",
    "version": "1.0.1",
    "websiteUrl": "https://icemoon.app/mcp"
  },
  "authentication": {
    "required": false
  },
  "tools": [
    {
      "name": "connect_device",
      "description": "Connect to a device by its server port and make it the ACTIVE device. Other pooled connections stay alive — switching devices is instant. Use list_devices to see available ports. Example: connect_device(port=8080)",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Port of the device server to make active."
          }
        },
        "required": [
          "port"
        ]
      },
      "annotations": {
        "title": "Connect device",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "delete_scheduled_task",
      "description": "Delete a scheduled calendar task by its id (from list_scheduled_tasks).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "task_id": {
            "type": "string",
            "description": "Id of the task, as returned by list_scheduled_tasks."
          }
        },
        "required": [
          "task_id"
        ]
      },
      "annotations": {
        "title": "Delete scheduled task",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "device_status",
      "description": "Connection status: active device + all pooled connections.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "Device status",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "disconnect_device",
      "description": "Disconnect a pooled device connection. port=0 disconnects the active one.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Device port to release; 0 releases the active device.",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Disconnect device",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "double_tap",
      "description": "Double-tap at coordinates (x, y).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "x": {
            "type": "number",
            "description": "X coordinate in points, in the device's portrait coordinate space."
          },
          "y": {
            "type": "number",
            "description": "Y coordinate in points, in the device's portrait coordinate space."
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "x",
          "y"
        ]
      },
      "annotations": {
        "title": "Double tap",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "find_by_id",
      "description": "Fast element lookup by accessibility identifier. Returns element frame and info if found, or success=false if not. Use this to verify which screen you're on (~50ms vs ~500ms for full tree). Example: find_by_id(\"share-sheet-share-button\") to confirm you're on the share screen.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "identifier": {
            "type": "string",
            "description": "Accessibility identifier of the target element."
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "identifier"
        ]
      },
      "annotations": {
        "title": "Find element by id",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "find_by_label",
      "description": "Find an on-screen element by TYPE and/or LABEL and pick one by VISUAL position. Either criterion alone works: type='Link' with no text → every link, and pick chooses which one (e.g. pick='3' = the 3rd link top-to-bottom). Use when several controls share the same action but differ only by a long or dynamic label — e.g. Amazon cart buttons whose accessible name is \"Save for later <full product title>\". Match the short action text and pick by position instead of spelling out the whole label. NB: only ON-SCREEN elements are in the tree — for the last cart item below the fold, scroll to the bottom first.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Substring to match against the element label.",
            "default": ""
          },
          "match": {
            "type": "string",
            "description": "'contains' (default) | 'prefix' | 'exact' | 'regex'.",
            "default": "contains"
          },
          "type": {
            "type": "string",
            "description": "Optional element-type filter, e.g. 'Button'.",
            "default": ""
          },
          "pick": {
            "type": "string",
            "description": "'last' (bottom-most, default) | 'first' (top-most) | '1'..'N' (nth, top→bottom).",
            "default": "last"
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Find element by label",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "foreach_elements",
      "description": "Loop over UI elements that share an ID pattern and act on each one — the reliable way to repeat a per-item flow without scripting each item. Two modes: • Numeric pattern (regex=False, default): id_pattern contains a placeholder '{i}' (or a trailing 'N'), e.g. 'inbox-thread-{i}' → resolves inbox-thread-0, inbox-thread-1, ... starting at `start`. • Regex (regex=True): id_pattern is a regular expression matched against the accessibility IDs currently on screen, e.g. r'^inbox-thread-\\d+$'. Per iteration: 1. resolve/find the element (numeric: by exact id; regex: next match), 2. if action=='tap', tap its center to open it, 3. run `after_each`: '' (stay), 'back' (return to the list via the back button or an edge-swipe), or a fingerprint id to wait for. Example (open the first 10 DM threads, returning to the inbox each time): foreach_elements('inbox-thread-{i}', action='tap', count=10, after_each='back') NOTE: this navigates/taps only. For richer per-item logic (type a message, tap a button, conditionals) build a foreach step in the Toolbox, whose 'Elements' mode uses the same pattern and exposes ${ElementIndex}, ${ElementId}, ${ElementLabel} to the nested actions.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id_pattern": {
            "type": "string",
            "description": "Identifier pattern: contains '{i}' (or a trailing 'N') in numeric mode, or a regular expression when regex=True."
          },
          "action": {
            "type": "string",
            "description": "What to do with each element: 'tap', or '' to visit without tapping.",
            "default": "tap"
          },
          "start": {
            "type": "integer",
            "description": "First index (numeric mode).",
            "default": 0
          },
          "count": {
            "type": "integer",
            "description": "How many items (0 = until an item is no longer found / no more matches).",
            "default": 0
          },
          "max_iter": {
            "type": "integer",
            "description": "Hard safety cap.",
            "default": 30
          },
          "after_each": {
            "type": "string",
            "description": "After each item: '' stays put, 'back' returns to the list, or an accessibility id to wait for.",
            "default": ""
          },
          "regex": {
            "type": "boolean",
            "description": "Treat id_pattern as a regular expression matched against on-screen ids.",
            "default": false
          },
          "scroll_when_missing": {
            "type": "boolean",
            "description": "If the next numeric id is not on screen, scroll down once and retry (for lists that lazy-load rows).",
            "default": true
          },
          "settle_ms": {
            "type": "integer",
            "description": "Settle time after each tap.",
            "default": 700
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "id_pattern"
        ]
      },
      "annotations": {
        "title": "For each matching element",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "get_2fa_code",
      "description": "Get a TOTP 2FA code. On the first call pass `secret` (base32) to register the account. Subsequent calls need only `account`. The code is also returned as `{{2fa:<account>}}` for use in smart_type regex substitution.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "account": {
            "type": "string",
            "description": "Account label the TOTP secret is stored under.",
            "default": "default"
          },
          "secret": {
            "type": "string",
            "description": "Base32 TOTP secret. Needed only on the first call for an account.",
            "default": ""
          }
        }
      },
      "annotations": {
        "title": "Get 2FA code",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "get_app_list",
      "description": "Get list of installed apps on the device. Optionally filter by name/bundleId substring.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Case-insensitive substring filter; empty returns every installed app.",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Get app list",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "get_element_at_position",
      "description": "Get the UI element at a specific screen position. Returns element details (type, label, frame, identifier).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "x": {
            "type": "number",
            "description": "X coordinate in points, in the device's portrait coordinate space."
          },
          "y": {
            "type": "number",
            "description": "Y coordinate in points, in the device's portrait coordinate space."
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "x",
          "y"
        ]
      },
      "annotations": {
        "title": "Get element at position",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "get_metrics",
      "description": "Get performance metrics for all tools: call count, error rate, avg/max latency.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "Get metrics",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_nav_map",
      "description": "Get the full navigation map for an app. Returns all screens, elements, flows. Use this to look up element coordinates, fingerprint IDs, and available flows. The AI should call this BEFORE attempting any interaction with a known app.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "app": {
            "type": "string",
            "description": "'instagram' or 'ios'",
            "default": "instagram"
          }
        }
      },
      "annotations": {
        "title": "Get nav map",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_screen_info",
      "description": "Get connected device screen size and server stats.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Device port to target; 0 (the default) uses the active device.",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Get screen info",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "get_screen_map",
      "description": "Get detailed info for a specific screen: elements with rel coords, fingerprints, actions. Returns all elements with their accessibility IDs and relative coordinates for tapping.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "app": {
            "type": "string",
            "description": "'instagram' or 'ios'."
          },
          "screen": {
            "type": "string",
            "description": "Screen name from get_nav_map() results"
          }
        },
        "required": [
          "app",
          "screen"
        ]
      },
      "annotations": {
        "title": "Get screen map",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "get_visible_elements",
      "description": "THIS IS YOUR EYES. Call this to see what's on the screen. Returns all visible UI elements with label, type, frame, identifier. Use frame coordinates to calculate tap targets: tap_x = frame.x + frame.width / 2 tap_y = frame.y + frame.height / 2 Always call this BEFORE any tap/swipe to know what to interact with. Args: max_depth: Snapshot tree depth (default 70). Higher = more elements but slower. port: target device port (0 = active device).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "max_depth": {
            "type": "integer",
            "description": "Maximum depth to walk the accessibility tree.",
            "default": 70
          },
          "port": {
            "type": "integer",
            "description": "Device port to target; 0 (the default) uses the active device.",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Get visible elements",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "http_request",
      "description": "Send an HTTP request from the device server.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Absolute URL to request. Loopback and private-network targets are rejected."
          },
          "method": {
            "type": "string",
            "description": "HTTP method, e.g. 'GET' or 'POST'.",
            "default": "GET"
          },
          "content_type": {
            "type": "string",
            "description": "Value for the Content-Type header.",
            "default": "application/json"
          },
          "headers": {
            "type": "string",
            "description": "Dict of HTTP headers (e.g. {\"Authorization\": \"Bearer ...\"}).",
            "default": null
          },
          "body": {
            "type": "string",
            "description": "Request body (for POST).",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "url"
        ]
      },
      "annotations": {
        "title": "HTTP request",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "identify_screen",
      "description": "Detect which screen is currently displayed by checking fingerprints from the nav map. Uses a single element-tree read, so cost does not grow with the number of screens. Returns the screen name, all available elements (with coords), and available actions. Use this when you need to know where you are before acting.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "app": {
            "type": "string",
            "description": "Mapped app to fingerprint against: 'instagram' or 'ios'.",
            "default": "instagram"
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Identify screen",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "keyboard_dismiss",
      "description": "Dismiss the on-screen keyboard.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Keyboard dismiss",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "kill_app",
      "description": "Close/terminate an app by name or bundle ID.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name_or_bundle_id": {
            "type": "string",
            "description": "App name or bundle identifier, e.g. 'Instagram' or 'com.burbn.instagram'."
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "name_or_bundle_id"
        ]
      },
      "annotations": {
        "title": "Kill app",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "list_devices",
      "description": "List all currently running iOS devices with their ports. Shows which devices are available and which are already connected (pooled). If only one device is running, it will be auto-connected on first use.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "List devices",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_saved_scripts",
      "description": "List automations saved to the library (available to schedule). Returns each script's name and step count. These are created from the Automation Studio UI via Save → To library.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "List saved scripts",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "list_scheduled_tasks",
      "description": "List all calendar tasks: name, script, target device, time, recurrence and status (pending/running/done/error/missed). Use to see what automations are scheduled and their outcomes.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "title": "List scheduled tasks",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "lock_device",
      "description": "Lock the device screen.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Lock device",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "navigate_to",
      "description": "Navigate from current screen to target screen using the nav map graph. Automatically: identifies current screen → finds shortest path (BFS) → executes each transition with wait_for verification → returns target screen elements. ONE call replaces 5-10 manual calls (get_screen_map + find_by_id + tap + wait + ...).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "app": {
            "type": "string",
            "description": "'instagram' or 'ios'.",
            "default": "instagram"
          },
          "target_screen": {
            "type": "string",
            "description": "Screen name from get_nav_map() (e.g. 'direct_inbox', 'reels_feed').",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Navigate to screen",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "open_app",
      "description": "Open an app by name (e.g. 'Safari') or bundle ID (e.g. 'com.apple.mobilesafari'). Names are resolved automatically.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name_or_bundle_id": {
            "type": "string",
            "description": "App name or bundle identifier, e.g. 'Instagram' or 'com.burbn.instagram'."
          },
          "wait_for": {
            "type": "string",
            "description": "Fingerprint ID — if set, polls until that screen appears after launch.",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "name_or_bundle_id"
        ]
      },
      "annotations": {
        "title": "Open app",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "pasteboard_get",
      "description": "Get the device clipboard content.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Pasteboard get",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "pasteboard_set",
      "description": "Set the device clipboard content.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "Text to place on the device clipboard."
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "content"
        ]
      },
      "annotations": {
        "title": "Pasteboard set",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "pinch",
      "description": "Pinch gesture at coordinates. scale < 1.0 = zoom out, scale > 1.0 = zoom in.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "x": {
            "type": "number",
            "description": "X coordinate in points, in the device's portrait coordinate space."
          },
          "y": {
            "type": "number",
            "description": "Y coordinate in points, in the device's portrait coordinate space."
          },
          "scale": {
            "type": "number",
            "description": "Zoom factor: below 1.0 pinches in, above 1.0 pinches out.",
            "default": 0.5
          },
          "velocity": {
            "type": "number",
            "description": "Negative = pinch in, positive = pinch out.",
            "default": -1.0
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "x",
          "y"
        ]
      },
      "annotations": {
        "title": "Pinch",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "plan_add_step",
      "description": "Append a new step to the plan (when you discover extra work mid-task).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Text of the step to append."
          },
          "plan_id": {
            "type": "string",
            "description": "Plan to act on; empty uses the most recent plan.",
            "default": ""
          }
        },
        "required": [
          "text"
        ]
      },
      "annotations": {
        "title": "Plan add step",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "plan_create",
      "description": "Create an execution plan BEFORE starting a multi-step task (3+ steps). Think ahead: break the task into concrete steps, then mark progress with plan_update_step as you go. The user sees the plan live in the dashboard.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "goal": {
            "type": "string",
            "description": "One-line description of what you are trying to achieve."
          },
          "steps": {
            "type": "string",
            "description": "Ordered list of step descriptions."
          },
          "device_udid": {
            "type": "string",
            "description": "Optional — bind the plan to a device (shown in the UI).",
            "default": ""
          },
          "task_id": {
            "type": "string",
            "description": "Optional — link the plan to a scheduled calendar task (id from list_scheduled_tasks / schedule_task).",
            "default": ""
          }
        },
        "required": [
          "goal",
          "steps"
        ]
      },
      "annotations": {
        "title": "Plan create",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "plan_get",
      "description": "Get the current plan and progress. plan_id defaults to the active plan. Call this after a long break or context loss to recall what you were doing and what remains.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "plan_id": {
            "type": "string",
            "description": "Plan to act on; empty uses the most recent plan.",
            "default": ""
          }
        }
      },
      "annotations": {
        "title": "Plan get",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "plan_update_step",
      "description": "Update a plan step as you make progress.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "step_index": {
            "type": "integer",
            "description": "Zero-based index of the step to update."
          },
          "status": {
            "type": "string",
            "description": "'in_progress' | 'done' | 'failed' | 'skipped' | 'pending'."
          },
          "note": {
            "type": "string",
            "description": "Optional detail (e.g. why a step failed or what was found).",
            "default": ""
          },
          "plan_id": {
            "type": "string",
            "description": "Defaults to the active plan.",
            "default": ""
          }
        },
        "required": [
          "step_index",
          "status"
        ]
      },
      "annotations": {
        "title": "Plan update step",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "press_button",
      "description": "Press a system button. Options: home, volumeUp, volumeDown.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "System button to press: 'home', 'volumeUp' or 'volumeDown'.",
            "default": "home"
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Press button",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "run_batch",
      "description": "Execute a SEQUENCE of actions on the device in ONE round-trip. Use this instead of separate tool calls whenever you already know the next 2+ steps and don't need to READ the screen between them (e.g. tap → wait_for → type_text, or N swipes with sleeps for reels). Returns per-action results + total elapsed_ms.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "actions": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "List of {\"command\": ..., ...params}. Supported commands: tap {x, y} · double_tap {x, y} · touch_hold {x, y, duration} tap_rel {rel: [0..1, 0..1]} — relative tap, expanded via screen size swipe {from_x, from_y, to_x, to_y, duration} — auto natural Bezier swipe_rel {from: [rx, ry], to: [rx, ry], duration} — relative swipe type_text {text, submit} · smart_type {text, submit} open_app {nameOrBundle} · kill_app {name} · home · press_button {name} keyboard_dismiss · lock_device · unlock_device find_element_by_id {identifier} · pasteboard_set {content} · pasteboard_get screenshot_save sleep {ms} — pause on the device server (max 10000) wait_for {identifier, timeout} — poll until id appears (max 15s)"
          },
          "stop_on_error": {
            "type": "boolean",
            "description": "Stop at the first failed action (default True).",
            "default": true
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active)",
            "default": 0
          }
        },
        "required": [
          "actions"
        ]
      },
      "annotations": {
        "title": "Run action batch",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "schedule_task",
      "description": "Schedule a saved automation to run on a device at a given time. The task runs on the device's Automation Studio page, which must be open and connected at the scheduled time.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "script_name": {
            "type": "string",
            "description": "Name of a script from list_saved_scripts."
          },
          "time_local": {
            "type": "string",
            "description": "Local time 'YYYY-MM-DDTHH:MM' (e.g. '2026-07-07T14:30')."
          },
          "device_udid": {
            "type": "string",
            "description": "Target device UDID, or '' for any connected device.",
            "default": ""
          },
          "recurrence": {
            "type": "string",
            "description": "'once', 'daily', or 'weekly'.",
            "default": "once"
          },
          "weekdays": {
            "type": "string",
            "description": "For weekly, list of day numbers (0=Sun..6=Sat).",
            "default": null
          },
          "name": {
            "type": "string",
            "description": "Optional display name (defaults to the script name).",
            "default": ""
          }
        },
        "required": [
          "script_name",
          "time_local"
        ]
      },
      "annotations": {
        "title": "Schedule task",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": false
      }
    },
    {
      "name": "screenshot_save",
      "description": "Save a screenshot PNG to the user's Desktop (for the user to view later). WARNING: This does NOT let you see the screen. You CANNOT view images. To understand what is on screen, use get_visible_elements instead.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Screenshot save",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "scroll",
      "description": "Scroll the screen at the given coordinates.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "x": {
            "type": "number",
            "description": "X coordinate in points, in the device's portrait coordinate space."
          },
          "y": {
            "type": "number",
            "description": "Y coordinate in points, in the device's portrait coordinate space."
          },
          "direction": {
            "type": "string",
            "description": "'up', 'down', 'left', or 'right'.",
            "default": "down"
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "x",
          "y"
        ]
      },
      "annotations": {
        "title": "Scroll",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "set_action_recording",
      "description": "Turn Action Container recording on/off on the device dashboard page. While enabled, every executed device action (taps, swipes, typing — including actions inside run_batch) is added as a step card to the Action Container, so the user gets a ready automation from what the AI did. ASK THE USER FIRST: before your first device action of a task, ask whether they want the actions recorded into the Action Container. Call set_action_recording(true) if yes; call set_action_recording(false) when the task is done or the user says stop. Don't re-ask in the same session unless the task changes. Requires the device page to be open in a browser (recording happens client-side). Returns recipients = number of connected page clients.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "True starts recording executed actions into the Action Container; False stops."
          },
          "port": {
            "type": "integer",
            "description": "Device port to target; 0 (the default) uses the active device.",
            "default": 0
          }
        },
        "required": [
          "enabled"
        ]
      },
      "annotations": {
        "title": "Record actions into the Action Container",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "set_location",
      "description": "Set simulated GPS location on the device.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "latitude": {
            "type": "number",
            "description": "Latitude in decimal degrees."
          },
          "longitude": {
            "type": "number",
            "description": "Longitude in decimal degrees."
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "latitude",
          "longitude"
        ]
      },
      "annotations": {
        "title": "Set GPS location",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "sleep_delay",
      "description": "Wait for the specified number of milliseconds before continuing. Useful between actions to let the device settle.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "ms": {
            "type": "integer",
            "description": "Pause length in milliseconds."
          }
        },
        "required": [
          "ms"
        ]
      },
      "annotations": {
        "title": "Sleep delay",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": false
      }
    },
    {
      "name": "smart_type",
      "description": "Type text using coordinate-based keyboard input (supports Russian & English). Uses visual keyboard detection — more reliable but slower than type_text.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Text to type. A {{2fa:<account>}} placeholder is replaced with a live TOTP code before typing."
          },
          "submit": {
            "type": "boolean",
            "description": "Press the keyboard's return key after typing.",
            "default": false
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "text"
        ]
      },
      "annotations": {
        "title": "Type (layout-aware)",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "swipe",
      "description": "Swipe from one point to another (absolute coords, natural Bezier curve).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "from_x": {
            "type": "number",
            "description": "X coordinate of the gesture's starting point, in points."
          },
          "from_y": {
            "type": "number",
            "description": "Y coordinate of the gesture's starting point, in points."
          },
          "to_x": {
            "type": "number",
            "description": "X coordinate of the gesture's end point, in points."
          },
          "to_y": {
            "type": "number",
            "description": "Y coordinate of the gesture's end point, in points."
          },
          "duration": {
            "type": "number",
            "description": "Swipe time in seconds (default 0.5).",
            "default": 0.5
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "from_x",
          "from_y",
          "to_x",
          "to_y"
        ]
      },
      "annotations": {
        "title": "Swipe",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "swipe_relative",
      "description": "Swipe using relative coordinates (0.0-1.0). Works on ANY iPhone model. ALWAYS use the coords from the screen's actions dict (from identify_screen/navigate_to). Example: swipe_relative(0.5, 0.85, 0.5, 0.15, 0.4) swipes down for next reel.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "from_x": {
            "type": "number",
            "description": "X coordinate of the gesture's starting point, in points."
          },
          "from_y": {
            "type": "number",
            "description": "Y coordinate of the gesture's starting point, in points."
          },
          "to_x": {
            "type": "number",
            "description": "X coordinate of the gesture's end point, in points."
          },
          "to_y": {
            "type": "number",
            "description": "Y coordinate of the gesture's end point, in points."
          },
          "duration": {
            "type": "number",
            "description": "Swipe time in seconds. Use the action's duration if provided, else 0.5.",
            "default": 0.5
          },
          "wait_for": {
            "type": "string",
            "description": "Fingerprint ID — if set, polls until that screen appears after the swipe.",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active)",
            "default": 0
          }
        },
        "required": [
          "from_x",
          "from_y",
          "to_x",
          "to_y"
        ]
      },
      "annotations": {
        "title": "Swipe relative",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "tap",
      "description": "Tap on the screen at coordinates (x, y). Coordinates are in screen points (e.g. 375x812 for iPhone).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "x": {
            "type": "number",
            "description": "X coordinate in points, in the device's portrait coordinate space."
          },
          "y": {
            "type": "number",
            "description": "Y coordinate in points, in the device's portrait coordinate space."
          },
          "wait_for": {
            "type": "string",
            "description": "Fingerprint ID — if set, polls until that screen appears after the tap.",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Target device port (0 = active device).",
            "default": 0
          }
        },
        "required": [
          "x",
          "y"
        ]
      },
      "annotations": {
        "title": "Tap",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "tap_by_id",
      "description": "Find element by accessibility ID and tap its center in one call. Faster than get_visible_elements + manual coordinate calculation + tap. Returns the element info and tap coordinates used.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "identifier": {
            "type": "string",
            "description": "Accessibility identifier of the target element."
          },
          "wait_for": {
            "type": "string",
            "description": "Fingerprint ID — if set, polls until that screen appears after the tap.",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active)",
            "default": 0
          }
        },
        "required": [
          "identifier"
        ]
      },
      "annotations": {
        "title": "Tap element by id",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "tap_by_label",
      "description": "Find an element by TYPE and/or LABEL + positional pick, then tap it in one call. Type alone is a valid criterion: tap_by_label(type='Link', pick='3') taps the 3rd link on screen (top-to-bottom). The label counterpart of tap_by_id — use it on web/dynamic screens where the accessible name embeds a product title (Amazon \"Save for later <title>\", etc.) so exact-id/exact-label matching is impractical. See find_by_label for match/pick semantics. Common: tap_by_label(\"Save for later\", match=\"prefix\", type=\"Button\", pick=\"last\") taps the bottom-most (last) item's button. Returns the tapped element + coordinates.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Substring to match against the element label.",
            "default": ""
          },
          "match": {
            "type": "string",
            "description": "'contains' (default) | 'prefix' | 'exact' | 'regex'.",
            "default": "contains"
          },
          "type": {
            "type": "string",
            "description": "Optional element-type filter, e.g. 'Button'.",
            "default": ""
          },
          "pick": {
            "type": "string",
            "description": "'last' (bottom-most, default) | 'first' (top-most) | '1'..'N' (nth, top→bottom).",
            "default": "last"
          },
          "wait_for": {
            "type": "string",
            "description": "Fingerprint ID — if set, polls until that screen appears after the tap.",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active)",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Tap element by label",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "tap_relative",
      "description": "Tap at relative coordinates (0.0-1.0). Automatically converts to absolute coords using device screen size. Works on ANY iPhone model. Example: tap_relative(0.5, 0.93) taps center of tab bar on all devices.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "rel_x": {
            "type": "number",
            "description": "Horizontal position as a fraction of screen width (0.0–1.0)."
          },
          "rel_y": {
            "type": "number",
            "description": "Vertical position as a fraction of screen height (0.0–1.0)."
          },
          "wait_for": {
            "type": "string",
            "description": "Fingerprint ID — if set, polls until that screen appears after the tap.",
            "default": ""
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active)",
            "default": 0
          }
        },
        "required": [
          "rel_x",
          "rel_y"
        ]
      },
      "annotations": {
        "title": "Tap relative",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "touch_hold",
      "description": "Long press (touch and hold) at coordinates (x, y).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "x": {
            "type": "number",
            "description": "X coordinate in points, in the device's portrait coordinate space."
          },
          "y": {
            "type": "number",
            "description": "Y coordinate in points, in the device's portrait coordinate space."
          },
          "duration": {
            "type": "number",
            "description": "Hold time in seconds (default 1.0).",
            "default": 1.0
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "x",
          "y"
        ]
      },
      "annotations": {
        "title": "Touch hold",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "type_text",
      "description": "Type text into the currently focused input field.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Text to type into the focused field."
          },
          "submit": {
            "type": "boolean",
            "description": "Press Enter/Return after typing.",
            "default": false
          },
          "clear_before": {
            "type": "boolean",
            "description": "Clear the field before typing.",
            "default": false
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "text"
        ]
      },
      "annotations": {
        "title": "Type text",
        "readOnlyHint": false,
        "destructiveHint": true,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "unlock_device",
      "description": "Unlock the device screen.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Unlock device",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "video_record",
      "description": "Start or stop video recording.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "description": "'start' or 'stop'.",
            "default": "start"
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        }
      },
      "annotations": {
        "title": "Video record",
        "readOnlyHint": false,
        "destructiveHint": false,
        "idempotentHint": false,
        "openWorldHint": true
      }
    },
    {
      "name": "wait_for_screen",
      "description": "Wait until a screen appears by polling its fingerprint ID. Returns immediately when found — no need for sleep_delay + find_by_id. Use after any action that triggers a screen transition.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "fingerprint_id": {
            "type": "string",
            "description": "Accessibility id that uniquely identifies the screen to wait for."
          },
          "timeout": {
            "type": "number",
            "description": "Max seconds to wait (default 5).",
            "default": 5.0
          },
          "poll_interval": {
            "type": "number",
            "description": "Seconds between polls (default 0.3).",
            "default": 0.3
          },
          "port": {
            "type": "integer",
            "description": "Device port (0 = active).",
            "default": 0
          }
        },
        "required": [
          "fingerprint_id"
        ]
      },
      "annotations": {
        "title": "Wait for screen",
        "readOnlyHint": true,
        "destructiveHint": false,
        "idempotentHint": true,
        "openWorldHint": true
      }
    }
  ],
  "resources": [],
  "prompts": []
}
