Skip to main content
Glama
ghost-in-the-droid

ghost-in-the-droid

Official

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
IOS_BUNDLE_IDNoDefault iOS app/browser bundle, e.g. com.google.chrome.ios or com.apple.mobilesafari
DEFAULT_DEVICENoADB serial (auto-detected if empty)
IOS_APPIUM_URLNoAppium server URLhttp://127.0.0.1:4723
OPENAI_API_KEYNoLLM features (Skill Creator, Agent Chat)
GITD_ENABLE_IOSNoEnable iOS support (set to '1' to enable)
IOS_DEVICE_UDIDNoiPhone or simulator UDID; devices are addressed as ios:<udid>
IOS_DEVICES_JSONNoPer-device iOS config for multiple phones/simulators, WDA ports, bundle IDs, and MJPEG ports
ANTHROPIC_API_KEYNoAlternative LLM provider
OPENROUTER_API_KEYNoOpenRouter LLM provider
IOS_MJPEG_SERVER_PORTNoWDA MJPEG stream port; use one unique port per iOS device

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
list_devicesA

List connected Android ADB devices and configured iOS Appium devices. Call this first to get the device serial you need for other tools.

screenshotA

Take a screenshot of the device screen. Returns a base64-encoded JPEG. Use this to SEE what's on screen before deciding what to tap.

Routes through the shared compressed screenshot path (half-resolution JPEG, cross-platform) instead of a raw full-res PNG: a raw PNG base64 string overflows the MCP tool-result token cap on content-heavy screens, so the client falls back to text/OCR and never sees the pixels. The downscale cuts the payload ~4-8x so most screens stay under the cap. (The lasting fix is returning an MCP image-content block; tracked as feature #8.)

get_elementsB

Get all UI elements on the current screen as a JSON array. Each element has: idx, text, content_desc, resource_id, class, bounds, center, clickable, scrollable. Use element idx with tap_element(). Call this to understand the screen layout before acting.

tapB

Tap at exact pixel coordinates (x, y) on the device screen.

tap_elementA

Tap a UI element by its index from get_elements(). Call get_elements() first to see what's on screen and get element indices.

swipeA

Swipe from (x1,y1) to (x2,y2). Use for scrolling, pulling down notifications, etc. Common patterns: scroll down = swipe(dev, 540, 1400, 540, 600) scroll up = swipe(dev, 540, 600, 540, 1400)

type_textA

Type text into the currently focused input field. Tap an input field first to focus it. Spaces are supported. Non-ASCII input is transliterated to the closest ASCII (adb input text is ASCII-only); for full-fidelity emoji/CJK use type_unicode() instead.

type_unicodeA

Type unicode text into the focused field. Android uses ADBKeyboard when configured; iOS uses WDA text entry. Use type_text() for plain ASCII.

press_backC

Press Back on Android or the best available iOS browser/navigation back action.

press_homeA

Press the platform Home button. Returns to the home screen.

press_keyA

Send a platform key event. Android accepts KEYCODE_* names, with the KEYCODE_ prefix added automatically. iOS supports WDA-backed HOME, ENTER/RETURN, and BACK/ESCAPE.

launch_appA

Launch an app by Android package name or iOS bundle id. Use search_apps() to find it.

Args: device: ADB serial or ios:. package: App package name or iOS bundle id, e.g. "com.android.chrome" or "com.google.chrome.ios". fresh: If True, force-stop the app first (cold start, clears in-memory state — back stack, unsaved drafts, login flow position, etc.). If False (default), reuses any existing background instance (warm start — resumes wherever the user left off). Use fresh=True for benchmarks, fresh start of a flow, or when the current app state would interfere with the task.

force_stopA

Force-stop an Android package or terminate an iOS bundle id.

app_stateA

Check whether an Android package or iOS bundle id is installed, running, or foreground.

open_cameraA

Open the platform camera app in a specific mode.

Android uses launcher/UI automation; iOS uses the Camera bundle and WDA UI controls. No package or bundle id is required.

Args: device: ADB serial or ios:. mode: One of: "photo" — rear camera, photo mode (default) "video" — rear camera, video/record mode "selfie" — front camera, photo mode "selfie_video" — front camera, video mode timer_s: Self-timer delay in seconds. Supported: 0 (off), 2, 3, 5, 10. Uses UI automation — snaps to the closest value the device supports (ASUS: 3s/10s, Samsung: 2s/5s/10s). 0 = no timer (default).

speak_textA

Make the phone speak text aloud using its built-in TTS engine.

Works whether the agent runs on the phone or on a PC — the call always goes through the Ghost portal app running on the device.

Args: device: ADB serial. This tool is Android-only. text: Text to speak. rate: Speech rate multiplier (0.5 = slow, 1.0 = normal, 1.5 = fast).

search_appsA

Search installed apps by name. Case-insensitive. Returns Android packages or iOS bundle ids. Example: search_apps('tiktok') → [{"name": "TikTok", "package": "com.zhiliaoapp.musically"}]

list_appsB

List installed apps with human-readable names and package names or bundle ids. iOS is limited to configured/common bundle ids verified through Appium.

list_packagesA

List raw Android package names or iOS bundle ids. Prefer list_apps() for display names.

long_pressB

Long press at coordinates. Use for context menus, drag initiation, etc.

get_phone_stateA

Get current app, activity, keyboard state, and focused element. Quick way to check what app/screen the device is on without parsing full elements.

device_healthC

Run a comprehensive device health check. iOS includes Appium/WDA status, active session details, and recovery steps.

fix_device_healthC

Apply a recovery action returned by device_health.recommended_fix.

get_screen_treeA

Get an LLM-friendly indented UI hierarchy of the current screen. Each node shows: [idx] ClassName "label" [clickable] [x1,y1][x2,y2]. Use this to understand screen layout and pick which element to tap. Much more readable than raw XML — prefer this over get_elements() for planning.

get_screen_xmlA

Get the raw normalized UI XML dump from the device. Android returns uiautomator XML; iOS returns normalized Appium/WDA XML. Use get_screen_tree() instead for a readable summary. Use this only when you need exact attribute values or the full hierarchy.

screenshot_annotatedA

Take a screenshot with numbered element labels overlaid on interactive elements. The numbers correspond to element indices from get_elements(). Use this when you want to SEE the screen with elements visually labelled. Returns base64-encoded PNG.

screenshot_croppedA

Take a screenshot of a specific region of the screen. Coordinates are in device pixels. Use this to zoom in on a specific area (e.g., a form field, a notification, a chart). Returns base64-encoded JPEG.

start_screen_recordingB

Start recording the device screen.

iOS uses WDA MJPEG captured through ffmpeg. Android uses adb screenrecord.

stop_screen_recordingC

Stop a running device screen recording and save the MP4.

screen_recording_statusB

Return active screen recording status for a device.

get_stream_infoB

Return effective stream metadata without opening the stream.

iOS reports WDA MJPEG URL/settings, screenshot fallback, and unsupported Portal/WebRTC actions. Android reports Portal/H264/screencap metadata.

ocr_screenA

OCR the entire device screen using RapidOCR. Returns all visible text with positions. Use this when UI elements are rendered as images/canvas (e.g., analytics dashboards, games, WebViews) where get_elements() returns no text. Returns JSON array of {text, conf, x, y, w, h} sorted top-to-bottom.

ocr_regionA

OCR a specific region of the screen. Coordinates in device pixels. More accurate than full-screen OCR for targeted text extraction. Returns JSON array of {text, conf, x, y, w, h} relative to the crop region.

classify_screenA

Classify the current screen: what app, what type of screen (home, search, profile, settings, dialog, error, loading), keyboard state. No LLM needed — uses XML heuristics. Use this for quick state checks before deciding what action to take.

toggle_overlayA

Toggle the numbered element overlay on the device screen. When on, interactive elements get visible numbered labels that match get_elements() indices. Useful for visual debugging or when sending screenshots to a vision model.

clipboard_getC

Get the current clipboard text from the device.

clipboard_setA

Set clipboard text on the device. Use with press_key(PASTE) to paste into fields.

paste_textA

Set clipboard text and immediately paste it into the currently focused field. Equivalent to clipboard_set + press_key(PASTE) in one call. Tap the target input field first to focus it, then call this.

get_notificationsA

Get active notifications. Returns JSON array of {package, title, text}.

open_notificationsC

Pull down the notification shade or iOS Notification Center.

clear_notificationsA

Dismiss visible notifications when the platform exposes a clear control.

web_searchA

Open a web search in whatever browser is on the device.

Faster than: launch Chrome → tap address bar → type → submit. Useful when the user asks "search for X" or you need to look up info that's not on the current screen. Picks the first installed browser from a fallback chain (Chrome → Firefox → Samsung Internet → Edge → Brave → Opera → Vivaldi → DuckDuckGo Browser → system default), so it works even if Chrome is missing.

Args: device: ADB serial or ios:. query: Free-text search terms (don't pre-escape — handled here). engine: "google" (default), "ddg" / "duckduckgo", "bing", or "brave". bundle_id: Optional iOS browser bundle id override, e.g. com.google.chrome.ios.

open_urlA

Open a URL in the platform browser.

On iOS this uses Appium/WDA and defaults to the configured browser bundle id, usually com.google.chrome.ios or com.apple.mobilesafari.

browser_backC

Navigate back in the current browser/app context.

get_current_urlC

Get the current browser URL when the platform exposes it.

wait_for_textC

Wait until text appears on screen and return visible text context.

extract_visible_textA

Extract visible text from the current screen with browser chrome filtered by default.

extract_articlesC

Extract likely visible article/headline candidates from the current browser page.

read_newsC

Open a news page and return structured headlines plus article snippets.

This is the iOS Chrome/WebDriver smoke workflow exposed as a single tool.

launch_intentA

Launch a full Android intent. More powerful than launch_app(). Examples: Open a URL: action="android.intent.action.VIEW" data="https://google.com" Open Settings: package="com.android.settings" Share text: action="android.intent.action.SEND" extras='{"android.intent.extra.TEXT": "hello"}'

find_on_screenA

Find specific text on the screen and return its location. Searches XML elements first (fast), falls back to OCR if not found. Use this to check if a button, label, or message is visible. Returns JSON with {text, x, y, w, h, method} or null if not found.

list_skillsA

List all installed mobile automation skills with their actions, workflows, and platform support. Use this to discover what high-level automations are available. Prefer using run_workflow() over raw tap/swipe when a skill exists for the task.

run_workflowA

Run an installed skill workflow on the device.

Call list_skills() first to see available skills and workflows.

Examples: run_workflow("SERIAL", "tiktok", "upload_video", '{"video_path": "/tmp/video.mp4"}') run_workflow("SERIAL", "send_gmail_email", "recorded", '{"subject": "Hello", "body": "Test"}')

params is a JSON string of keyword arguments for the workflow.

run_actionA

Run a single skill action on the device.

Call list_skills() first to see available actions.

Examples: run_action("SERIAL", "tiktok", "open_app", '{}') run_action("SERIAL", "tiktok", "type_and_search", '{"query": "cats"}')

run_flowA

Run an ordered batch of tool calls server-side in ONE round-trip.

steps is a JSON list of {"tool": "", "args": {...}} — the same tool names execute_tool exposes (tap, tap_element, type_text, launch_app, etc.). Steps run in order and stop at the first error. Returns a JSON object with per-step results and a SINGLE final screenshot (not one per step) — far fewer tokens/round-trips than calling each tool separately. Steps do NOT auto-settle between UI actions; if a step needs the screen to update before the next one reads it, insert an explicit {"tool":"wait","args":{...}} step.

Example: run_flow("SERIAL", '[{"tool":"launch_app","args":{"package":"com.android.settings"}}, {"tool":"find_on_screen","args":{"text":"Wi-Fi"}}, {"tool":"tap","args":{"x":540,"y":300}}]')

Security: fail-closed allow-list — only vetted read/UI tools may run inside a flow. Anything else (raw shell, run_skill, or any unknown tool) makes the whole flow be refused before any step runs, since a batch is exactly where an injected instruction would smuggle a shell command. Max 50 steps.

list_crashesA

List recent app crashes and ANRs (from the logcat crash buffer, no root).

Android-only: iOS crash logs need syslog/CrashReporter access, not exposed yet. Optionally filter by package (substring match on the crashing process). Returns JSON: {count, crashes: [{type, timestamp, process, summary}]}. Use get_crash() to pull a full stack for the most recent one.

get_crashA

Return the full stack trace of the MOST RECENT crash (from the crash buffer).

Android-only: iOS crash logs need syslog/CrashReporter access, not exposed yet. Optionally filter by package. Pair with list_crashes() to see what's there.

waitB

Pause execution for a fixed number of seconds.

explore_appA

Explore an app's UI autonomously using BFS. Launches the app, taps every interactive element, builds a state graph. Returns JSON with discovered screens, elements, and transitions. Use this to understand an unfamiliar app before writing automation for it.

create_skillA

Create a new reusable skill from a JSON list of recorded steps.

steps is a JSON array like: [ {"action": "launch", "package": "com.example.app", "description": "Open app"}, {"action": "tap", "x": 540, "y": 1200, "description": "Tap button"}, {"action": "type", "text": "hello", "description": "Type greeting"}, {"action": "wait", "seconds": 2, "description": "Wait for load"} ]

Supported actions: launch, tap (x,y or element_idx), type, swipe, back, home, wait. For iOS skills, pass platforms="ios" and either app_package or ios_bundle_id as the bundle id. Optional elements_ios/elements_android are JSON selector maps written to elements_ios.yaml/elements.yaml. After creating, use run_workflow(dev, name, "recorded", params) to replay it.

draft_skillA

Distil the device's most recent chat conversation into draft replayable steps for a HARD skill.

Returns the captured steps (with correct coords/args), a guessed app_package, and a summary. Nothing is written — review/prune/rename the steps, then call save_skill(kind="hard", steps=...).

save_skillA

Save the device's current chat conversation as a reusable skill.

kind="hard" replays concrete actions — pass revised steps (a JSON array from draft_skill), or omit them to auto-distil the conversation. kind="soft" stores markdown guidance (what to watch out for) surfaced to agents on demand via list_skills / run_workflow.

lookup_leadA

Get the full fact sheet for one influencer lead by handle.

Use this when you need to know everything about an influencer to draft a personalised reply or decide next-step outreach: their follower count, engagement, bio, niche, what hashtag we found them on, when we DMed them, which account sent the DM, their latest reply, and unread state.

Args: handle: TikTok username, with or without @ (e.g. 'creatorhandle' or '@creatorhandle')

list_unread_leadsA

List every influencer with an unread reply in the inbox, sorted by recency.

Returns one row per unread conversation with the handle, unread count, last message preview, and timestamp. Useful for daily prioritisation: 'which leads should I respond to right now?'

crm_lookup_contactA

Get the stored fact sheet for one local CRM contact by handle. Read-only.

Returns the contact's profile fields, contact status/history, and the latest conversation state (last message, unread count, timestamps).

Args: handle: Contact handle, with or without @.

crm_list_unread_messagesA

List local CRM contacts with unread messages, sorted by recency. Read-only.

Returns one row per unread conversation with the handle, unread count, last message preview, and timestamp.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

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/ghost-in-the-droid/android-agent'

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