MCP server
The same 27 tools, two ways in: a hosted MCP endpoint (URL + your API key, nothing to install or keep current) and a local stdio server in one stdlib-only Python file. Agents that speak the Model Context Protocol get PreviewAPK as native tools — including screenshots that return as images inside the conversation.
Hosted MCP — no install
Point your MCP client at https://previewapk.siteport.site/mcp with your account API key as a Bearer token. The server speaks MCP Streamable HTTP (2024-11-05 and 2025-03-26) and answers with the same tools, the same receipts, and the same error envelopes as the local server — your key's scope is enforced identically (a read-only key observes here and cannot drive).
Claude Code
claude mcp add --transport http previewapk https://previewapk.siteport.site/mcp \
--header "Authorization: Bearer <your key>"
Cursor / generic remote-MCP clients
{
"mcpServers": {
"previewapk": {
"url": "https://previewapk.siteport.site/mcp",
"headers": { "Authorization": "Bearer <your key>" }
}
}
}
Codex
# ~/.codex/config.toml — with PREVIEWAPK_API_KEY set in the environment
[mcp_servers.previewapk]
url = "https://previewapk.siteport.site/mcp"
bearer_token_env_var = "PREVIEWAPK_API_KEY"
How selection works here: at connect, the server issues a session id (Mcp-Session-Id) and your working-device selection rides on it — select once with previewapk_use_device (or start a device), then drive, exactly like the local server. Two connections never share a selection, even on the same key. Selections live in the server's memory: they survive about two idle hours and are forgotten on a server restart (select again — nothing else is lost). Calls that name their device also work with no session at all.
Hosted differences — the server cannot read your disk: previewapk_push_apk takes apk_b64 (the file as base64) instead of path; previewapk_device push_file takes data_b64 instead of a local path, and pull_file returns the content as data_b64; previewapk_record_download returns the MP4 as data_b64 instead of writing a file. Request bodies cap at 25 MB and inline downloads at ~25 MB — for very large APKs or recordings, the CLI's resumable transfers are the right tool.
Local install (stdio)
curl -o previewapk_mcp.py https://previewapk.siteport.site/mcp/previewapk_mcp.py
Claude Code
claude mcp add previewapk \
--env PREVIEWAPK_API_KEY=<your key> \
-- python3 /path/to/previewapk_mcp.py
Cursor / generic MCP clients
{
"mcpServers": {
"previewapk": {
"command": "python3",
"args": ["/path/to/previewapk_mcp.py"],
"env": { "PREVIEWAPK_API_KEY": "<your key>" }
}
}
}
Google Antigravity
PreviewAPK is not in Antigravity's built-in MCP Store — Google curates that shelf itself, and there is no submission path. The raw-config route below takes about two minutes and works the same in the Antigravity IDE, App, and CLI, which all share the one config file (~/.gemini/config/mcp_config.json).
In the IDE: open the agent panel's … menu → MCP Servers → Manage MCP Servers → View raw config, and add the entry:
{
"mcpServers": {
"previewapk": {
"command": "python3",
"args": ["/path/to/previewapk_mcp.py"],
"env": { "PREVIEWAPK_API_KEY": "<your key>" }
}
}
}
Save, then click Refresh in the MCP servers panel. Antigravity's agent gets the same 27 tools listed below, screenshots included.
The working-device model: an agent session has a working device, like a working directory. previewapk_use_device selects it (or previewapk_start, which requires naming the device and selects it too); every other tool then talks to the working device without repeating its name, and a per-call device argument overrides for one call. With nothing selected, action tools refuse — there is no default device to guess. Each agent session holds its own selection, so two agents on one account never inherit each other's place.
Tools
| Tool | Arguments | Returns |
|---|---|---|
previewapk_list_devices | — | Every device on the account — name, id, profile, Android, status, attached app, and which one is your working device |
previewapk_use_device | device | Select the working device (the cd) — later tools talk to it without naming it |
previewapk_status | device? | Device state (the API's device object) — including the handoff block while the agent waits for a human step, the filed finish_report, and — exactly once after a handback — handback_note + resumed |
previewapk_push_apk | path, device?, run?, driver? | Attach result + app label/version. On a running device (you hold the wheel) the build is hot-swapped in live — no reboot |
previewapk_start | device (name or id), driver? (agent default) | Session starting confirmation |
previewapk_stop | device? | Stopped confirmation |
previewapk_get_links | device? | {status, driver, driver_changed_at, driver_note, handoff, finish_report, session_url} |
previewapk_tap | x, y (0–1 fractions), device? | OK / driver-gating error |
previewapk_swipe | x1, y1, x2, y2, ms?, device? | OK |
previewapk_press_key | code (Android keyevent), device? | OK |
previewapk_type_text | text, device? | OK — fails honestly when no field is focused |
previewapk_relaunch | device? | Bring the app back to the foreground (about 2s, no reboot) |
previewapk_screenshot | device? | An image of the current screen (PNG content block, the real screen) — the agent can look at it |
previewapk_get_logs | since_seconds?, lines?, errors_only?, contains?, device? | The app's logcat for this session (or the saved tail after it ends) — check after actions; a crash's exact reason lives here |
previewapk_hierarchy | device? | The screen as an element tree (text outline) — navigate and assert without image tokens |
previewapk_tap_text | text, index?, device? | Tap the element with that label (text or content-desc), resolved by the hierarchy |
previewapk_handoff | driver (agent|user), device? | New driver confirmation |
previewapk_observe | screenshot?, scale?, device? | A compact numbered snapshot of the screen (snapshot_id, foreground app, keyboard state, elements with refs) — the cheap default read. With screenshot: true, the frame comes back as an image too |
previewapk_act | actions (max 20), observe?, device? | Run a batch of actions in order; stops at the first failure and returns per-action results. Never replay a batch whose outcome you don't know |
previewapk_wait_for | condition? (element|driver), text?, desc?, id?, present?, timeout_s?, device? | Wait until an element is present (or gone). {found, waited_ms} — found: false at the timeout is a result, not an error. With condition: "driver": wait until the human hands the wheel back (default timeout 300s) — the result carries the handback note |
previewapk_request_human | reason, device? | Ask the human for a step only a human should do (password, 2FA, payment, CAPTCHA). Returns message_for_human — relay it verbatim, then wait with previewapk_wait_for condition driver |
previewapk_finish | summary, verdict? (passed|failed|mixed), end_session? (default false), device? | File the session wrap-up; returns message_for_human with the server's own counts (duration, actions, errors) — relay it verbatim. The report is stored on the session and its archive |
previewapk_feedback | worked?, broke?, wish?, workaround?, rating?, device? | File a field report — read and tallied, and they set the roadmap. Refused when the account opted out of diagnostic sharing |
previewapk_record_start | name?, device? | Start recording the screen (MP4; one recording caps at 180s) |
previewapk_record_stop | device? | Stop the recording; the MP4 is pulled to the server and indexed (rec_id, size, duration) |
previewapk_record_download | path (local file), rec_id?, device? | Download a finished recording to a local file — resumable; recordings stay downloadable after the session ends. Hosted MCP: returns data_b64 instead of writing a file |
previewapk_device | action: set_timezone (tz) · set_locale (locale, package?) · set_location (lat, lon) · clear_location · push_file / pull_file (local_path, remote_path; 10 MB cap) · list_files · delete_file · reboot | Device controls for realistic QA: timezone, per-app language, mock GPS fix, fixture files in shared storage, and a data-preserving phone restart. No clipboard action — not available on these phones |
The workflow that makes this worthwhile: push → start (agent-driven) → screenshot → fix what looks wrong → rebuild → handoff to user → present the session link from previewapk_get_links. The agent verifies its own UI work against real pixels before a human ever sees it. The agent guide has the full briefing to give your agent.