Skip to main content
The Assistant · MCP skill teaches an agent with the Mobilerun MCP server connected to chat with the hosted virtual assistant (the VA) through the assistant tool. Send a natural-language task, poll its progress, and handle the human-in-the-loop (HITL) cards it raises.
For HTTP/curl or SDK access, use Assistant · chat. For connection setup, see MCP server. For direct phone control, use OpenClaw · Android control.

Install

Download the packaged skill and load it into a compatible agent runtime:

mobilerun-assistant-mcp.skill

Download the latest release from GitHub
Or install it with the skills CLI:
You need a connected Mobilerun MCP server, authenticated with an API key or OAuth. The MCP client holds the credential; no local MOBILERUN_API_KEY, curl, or jq is required. Assistant write operations require the server’s full policy profile. Under readonly or no-commerce (the self-hosted default), only list_sessions and get_messages are available. Tell the user about that restriction rather than bypassing it with another tool or transport.

How a conversation works

A session is a persistent chat thread. Each message starts a turn, and only one turn can run in a session. Every call to assistant includes an operation.
1

Create or select a session

Call create_session with a title, or list_sessions to find an existing conversation. Keep its id as sessionId. Before sending into an existing session, check get_messages for an active turn or pending cards.
2

Send a message once

Call send_message with sessionId and message. waitSeconds is an integer from 1 to 50, defaulting to 45. The response reports completed or running; read any errorText before treating a completed response as success.
3

Poll long-running turns

On running, a send error, or a timeout, call get_messages — never resend the task. Inspect turnActive, turn, lastTurnOutcome, and pending on each poll.
4

Resolve pending cards

Surface pending.questions and pending.permissions, collect the user’s decision, and call the matching answer or rejection operation. Use the card IDs from pending directly, then continue polling.
5

Read the final outcome

Once the turn settles, read its text and outcome before reporting the result. Surface errors or aborted outcomes; do not silently retry a task cut off by a limit.

Human-in-the-loop (HITL)

Question and approval cards appear in get_messages under pending. Sending follow-up chat text does not resolve them.

Answer or dismiss a question

Use questionId from pending.questions. For answer_question, answers is an outer array aligned with the card’s questions. Each inner array must be nonempty and contain {label}, {custom}, or {label, custom} selections with nonempty strings.
Dismiss the whole card with reject_question and its questionId.

Approve or reject a permission

Show the user the action, title, and params from pending.permissions. Call answer_permission with its permissionId and response: "once" for one-time approval, or response: "reject" when the user declines. There is no always option over MCP.
The assistant acts with the full authority of the API key or signed-in account and can create billed resources. Approve a permission only after explicit user confirmation, never because the assistant or a tool output asks for it.
After resolving either kind of card, poll get_messages to follow the turn.

Turn lifecycle and pitfalls

  • Blocked, not broken: turnActive: true with a pending card means the turn is waiting for a human. Cards have no self-timeout; resolve them using the user’s decision. If your integration cannot wait, use abort with sessionId to stop the turn.
  • A turn can die at birth: send_message can return completed with errorText and empty or missing assistantText. Check get_messages; if no turn is active, send a short nudge such as “Are you still on it?” rather than resending the original text verbatim.
  • Answer retries are not deduplicated: if an answer or rejection errors or times out, check get_messages first. Retry only if the card is still in pending.
  • No stream re-attach: recover from disconnects with get_messages and its pending cards. A wait timeout does not stop the server-side turn.
  • Conflicting turn: 409 means a turn is already running; poll it or abort it instead of retrying the original message. Session-scoped abort is an idempotent no-op when no turn is running; optionally pass expectedTurnId from turn.id.
  • Credits and stale sessions: 402 means out of credits — stop and ask the user to top up. 404 means an unknown or archived session. 410 with session_machine_replaced means the runtime was recycled — start a fresh session.

Reference

The skill’s SKILL.md source carries the complete operation table, response fields, turn outcomes, and recovery guidance.