FAQ and troubleshooting

Answers to the questions people actually hit

Everything here comes out of the source: the repo's troubleshooting notes, the tool definitions on the MCP server, and the Android module's own build configuration. Where a published claim disagrees with the code, the code wins and the answer says so.

18 questions, answered from the source.

Requirements and cost

What Android version do I need to run the Aster companion app?

The Aster Android companion app requires Android 8.0+ (API 26), because apps/android/app/build.gradle.kts sets minSdk = 26 and API 26 is Android 8.0 Oreo. A phone on Android 7 cannot install it at all. The app compiles against and targets API 36, ships an arm64-v8a build, and needs its Accessibility Service switched on by hand after install — that toggle, not the OS version, is what actually unlocks screen control.

Does Aster need root, a custom ROM or USB debugging?

Aster needs none of those: it runs on a stock, unrooted phone. Screen control comes from an Android AccessibilityService, notifications from a NotificationListenerService, and everything else from ordinary runtime permissions you grant in the app — all of them public Android APIs. There is no root requirement, no custom ROM, no ADB shell and no USB cable in the loop; the phone reaches the server over the network, which is the main practical difference from scrcpy and raw ADB.

Is Aster free? What is the licence?

Aster is free and open source under the MIT licence — both halves of it, the Node MCP server published to npm as aster-mcp and the Android companion app. There is no account to create, no paid tier, no licence key and no usage metering, because Aster is self-hosted: you run the server on your own machine, so there is nothing for anyone to bill. The only costs you can incur are the ones your own AI client already has, such as tokens billed by whichever model provider it talks to.

Does Aster work with an iPhone or an iPad?

No. Aster is Android only, and not by omission — it drives the phone through Android's AccessibilityService and NotificationListenerService, and reads SMS, contacts and call state through Android content providers. iOS exposes no equivalent to a third-party app, so there is nothing to port. The companion is an Android APK (Android 8.0+ (API 26), arm64-v8a); the aster-mcp server itself runs on macOS, Linux or Windows, but the phone at the other end has to be an Android device.

Can one server drive more than one phone?

Yes. Devices are addressed individually: every tool but one takes a deviceId, and the exception is aster_list_devices, which takes nothing and returns every paired phone with its connection status so your assistant can pick one. Each phone holds its own WebSocket to the same server and is approved separately, so a spare handset dedicated to the AI and your daily phone can be paired at once with different approval states. This is the one thing the on-device modes cannot do — aster_list_devices is the single server tool with no on-device equivalent, because brokering between phones is meaningless on the phone itself.

Is the Aster app on the Google Play Store?

No. The companion app is distributed as an APK from GitHub Releases and installed by sideloading — an accessibility app that can read the screen and drive other apps is not a comfortable fit for Play's policies, and shipping it as a signed release you install deliberately is the honest packaging. Android will ask you to allow installs from that source once. The server half is on npm as aster-mcp, which needs no such step.

How do I update Aster once it is installed?

The two halves update separately. For the server, `npm install -g aster-mcp` again — it is an ordinary global npm package, so the same command installs and upgrades; `aster --version` tells you where you are. For the phone, download the newer APK from Releases and install it over the existing one; the signature matches, so it upgrades in place and keeps your approvals, permission grants and the accessibility toggle. Approved devices survive both, because the approval lives in the server's database, not on the handset.

Connecting and troubleshooting

My device shows as connected but every command fails or times out. Why?

A device that shows as connected in Aster but times out on every command is almost always still pending approval, because connecting and being approved are two separate states. A new phone self-reports its identity (a hashed Android ID, its name and model) and lands as pending: connected, but hard-blocked — the server refuses every command for any device whose status is not approved. Approve it from the dashboard at http://localhost:5989, or run "aster devices approve DEVICE_ID" on the server. A device you reject instead is disconnected with WebSocket close code 4003.

The device disconnects when I switch between Wi-Fi and mobile data. How do I fix it?

The Aster companion app now reconnects by itself after a Wi-Fi or mobile-data switch: it backs off and retries, showing "Reconnecting" in the app, instead of sitting on a socket that died with the old network. If it never comes back, the problem is the address rather than the socket — "aster status" advertises a LAN IP that is only valid on the network the server was started on, so the phone is retrying an address that no longer exists. Keep both ends on one network, or point the app at a stable Tailscale address so the server's address survives the switch.

Which ports does Aster need open in my firewall?

Aster listens on three local ports: 5987 is the WebSocket device link the phone connects to, 5988 is the API plus MCP HTTP endpoint that serves POST /mcp and the health route, and 5989 serves the web dashboard on the server machine. In practice the phone needs to reach 5987 and your AI client needs to reach 5988; 5989 only has to be reachable from whatever browser you open the dashboard in. Allow those on your LAN or your Tailscale network, and do not port-forward any of them to the public internet — there is no shared secret on the device link, so exposure is the whole risk.

How do I check that the Aster server is reachable from a script?

To check an Aster server programmatically, request its health endpoint: "curl http://localhost:5988/api/health" returns a small JSON body with a status of ok and a timestamp, so a non-zero exit or a missing ok is your liveness signal. For device counts, GET /api/stats on the same port returns the registry totals. For a human-readable snapshot instead, run "aster status" on the server: it prints the advertised LAN address, the listening ports and the connected devices with their approval state.

Security and privacy

Is the connection encrypted? Do I need SSL?

The Aster device link is not encrypted by default: on a trusted LAN the phone connects over plain ws:// to port 5987, and the Node ws server does not terminate TLS itself, so aiming wss:// at that port with nothing in front of it fails with a TLS parse error rather than upgrading. For remote or encrypted access you put the encryption in front of the socket — Tailscale Serve gives the app a wss:// MagicDNS address while MCP stays plain HTTP on the Tailscale IP at port 5988, or you terminate TLS at Traefik or Caddy and proxy to ws:// on localhost. Encryption for remote control therefore comes from WireGuard or from your own TLS terminator, never from a padlock on the Node socket.

Does Aster send my data anywhere?

Aster sends nothing anywhere: it has no telemetry, no analytics and no vendor relay. The server runs on hardware you own, the device registry and logs live in a local SQLite file next to it, and your AI client reaches the tools over a local MCP HTTP endpoint on your own network. The single outbound call Aster can make is the optional event-forwarding webhook, which stays off until you run "aster set-event-forwarding" and then POSTs only to the URL you supplied. Your AI client is a separate question: if it is backed by a hosted model, that client still sends your prompts — and whatever screenshots or text Aster hands back — to its own model provider.

Can the AI open or control my banking apps?

Aster blocks AI screen control over banking and payments apps by default, through an on-device guard called PackagePolicyGuard that runs regardless of what the AI asks for. It is fail-closed: it ships a bundled denylist covering apps such as PhonePe, Paytm, PayPal, Venmo and Binance, it refuses control actions while one of those is in the foreground unless you have explicitly allowed that app, and it also refuses when the foreground app cannot be identified at all. The guard gates acting rather than looking — read-only actions such as observe, screenshot, view hierarchy and find element stay permitted — so treat it as a control block rather than a blindfold, and use the persistent kill-switch notification to end a screen-control session in one tap.

Where does Aster store my data, and how do I delete it?

Two plain files on the machine running the server, and nothing anywhere else. Devices, approvals and tool-call logs go into a SQLite database at `./aster.db` — resolved relative to the directory you ran `aster start` from, or wherever the `DB_PATH` environment variable points. Runtime state lives in `~/.aster`: `~/.aster/status.json`, `~/.aster/aster.pid`, and `~/.aster/event-forwarding.json` if you turned forwarding on. Stop the server and delete both and nothing of Aster's remains. There is no cloud copy, no account and therefore no deletion request to file.

Tools and behaviour

How many tools does Aster have, and what are they called?

The number depends on which surface you are talking to. The Aster MCP server registers 49 tools, and every one of them carries the aster_ prefix — an MCP client sees aster_take_screenshot, aster_send_sms and aster_make_call_with_voice, so calling take_screenshot without the prefix is not a valid tool name. The on-device catalog used by the app's own MCP server and by Binder IPC is a different set of 77 unprefixed actions, and neither catalogue contains the other. 48 of the on-device actions are reachable from an MCP client, 29 are not — observe, tap, scroll, set_text, perform, press_key, the wait verbs, three of the four overlay verbs, the companion-face verbs, and the screen_* human-in-the-loop verbs. Going the other way, exactly 1 server tool has no on-device counterpart, aster_list_devices, because brokering between phones is meaningless on the phone itself; aster_click_by_id looks like a second one but is only a rename of the device action click_by_view_id. Quoting a single number without naming the surface is what makes tool counts wrong.

The AI placed a call but the other side heard no audio. What went wrong?

When aster_make_call_with_voice dials successfully but nobody hears the message, that is usually the design rather than a fault: the text is spoken by the phone's own text-to-speech over the loudspeaker and reaches the call by acoustic coupling — the loudspeaker feeding the call microphone — because Android does not let an app inject audio into the call path. It follows that quality is device-dependent and a quiet room matters a great deal. Check that CALL_PHONE, READ_PHONE_STATE and MODIFY_AUDIO_SETTINGS are granted, that the phone is not on silent and the call audio is not routed to a headset or a car, and remember the tool waits for the call to be answered before it speaks (8 seconds by default, adjustable with the waitSeconds parameter).

Why does the Aster app have no chat screen?

The Aster app has no chat screen on purpose. Aster is the device-side companion that holds the sensitive permissions — accessibility, SMS, contacts, files, camera — so it stays deliberately small and auditable, with no model providers, no API keys and no conversation storage inside the app that holds those permissions. The app you chat with is OpenAlly (https://openally.ai), which drives Aster on the same phone over Binder IPC, so in practice there is no app-switching: you type in OpenAlly and Aster does the device work. Any other MCP client — Claude Code, Claude Desktop, AnythingLLM, OpenClaw — reaches exactly the same tools through the server or through the on-device MCP mode.

Why not just scrcpy or ADB?

Both are excellent — for a person at a keyboard with a USB cable. Aster solves a different problem: it is not a screen mirror but a tool layer an AI agent calls by name, with the approval gate and kill switch a mirror was never meant to have.

Aster compared to scrcpy and raw ADB
Aspectscrcpy / raw ADBAster
ConnectionA USB cable, or USB debugging enabled over the LANA companion app over the network, with no USB debugging
Remote accessNeeds tunnelling or ADB-over-TCP set up by handWorks from anywhere over Tailscale, with no port forwarding
InterfaceA mirrored screen plus raw shell commandsHigh-level MCP tools an AI calls by name: aster_take_screenshot, aster_click_by_text, aster_send_sms, aster_make_call_with_voice
Built forA person driving the phone manually at a keyboardAn AI agent acting on its own, behind an approval gate and a kill switch
Safety railsNone beyond what the shell itself enforcesPer-device approval, a fail-closed banking denylist, and a persistent stop notification
EventsPull only — you ask, it answersPushes SMS and notification events to your AI as they arrive

Still stuck?

Run these three checks on the machine hosting the server before you open an issue. Between them they separate the three failures that account for nearly everything: the server is not running, the device is connected but not approved, or the phone is pointed at an address that no longer exists.

  1. Confirm the server is up and note the LAN address it advertises — that is the address the phone must be able to reach.
  2. Check the device's approval state. A device listed as pending is connected and still refused on every command.
  3. Hit the health endpoint from wherever your AI client runs, not just from the server itself — that is what proves the path, not the process.
Diagnostics
aster status
aster devices list
curl http://localhost:5988/api/health

Where to go next