Computer Use APIv1

Give your code
eyes and hands.

Send a screenshot. Get structured mouse and keyboard actions back. One REST endpoint — for automation, browser testing, and AI agents that interact with any GUI.

3.5s
median step latency
10
action primitives
99.9%
uptime SLA
One call. Four lines.

Built for any stack.

Pure REST. No SDK lock-in, no extra servers, no browser drivers.

POST /v1/predict
1import requests, base64
2 
3img = base64.b64encode(open("screen.png", "rb").read()).decode()
4 
5r = requests.post(
6 "https://coasty.ai/v1/predict",
7 headers={"X-API-Key": "sk-coasty-live-..."},
8 json={
9 "screenshot": img,
10 "instruction": "Click the search bar and type 'hello'",
11 },
12)
13 
14for a in r.json()["actions"]:
15 print(a["action_type"], a["params"])
Returns a stream of typed actions — coordinates, keystrokes, and confidence.
Machines API

Real desktops. Real shells. Real automation.

Provision a sandbox or production VM, then drive it with actions, terminal commands, browser automation, or file ops. One auth header, fifteen endpoints.

POST /v1/machines + POST /v1/machines/{id}/actions
1import requests
2 
3# Provision a sandbox VM (sk-coasty-test-* — instant, no AWS, no billing).
4r = requests.post(
5 "https://coasty.ai/v1/machines",
6 headers={
7 "X-API-Key": "sk-coasty-test-...",
8 "Idempotency-Key": "demo-001",
9 },
10 json={
11 "display_name": "automation-bot",
12 "os_type": "linux",
13 "desktop_enabled": True,
14 },
15)
16machine = r.json()["machine"]
17 
18# Drive it: click at (512, 340)
19requests.post(
20 f"https://coasty.ai/v1/machines/{machine['id']}/actions",
21 headers={"X-API-Key": "sk-coasty-test-..."},
22 json={"command": "click", "parameters": {"x": 512, "y": 340}},
23)
Sandbox keys (sk-coasty-test-*) return a mock VM in < 50 ms — instant retries, zero AWS cost.
POST /v1/machinesGET /v1/machinesDELETE /v1/machines/{id}POST /v1/machines/{id}/startPOST /v1/machines/{id}/stopPOST /v1/machines/{id}/snapshotGET /v1/machines/{id}/screenshotGET /v1/machines/{id}/connectionPOST /v1/machines/{id}/actionsPOST /v1/machines/{id}/actions/batchPOST /v1/machines/{id}/browser/{op}POST /v1/machines/{id}/terminalPOST /v1/machines/{id}/files/{op}
Schedules API

Cron, webhooks, email, chains.

Run an agent on a cron, fire it from any webhook with HMAC, or chain schedules together. Per-fire 10 cr/min · webhook routing 1 cr / 200 fires · sandbox is free.

POST /v1/schedules  +  POST /triggers (webhook)  +  sign & fire
1import requests, hmac, hashlib, time
2 
3# 1. Create a daily 9 AM ET schedule
4sched = requests.post(
5 "https://coasty.ai/v1/schedules",
6 headers={"X-API-Key": "sk-coasty-test-..."},
7 json={
8 "name": "morning briefing",
9 "machine_id": "550e8400-e29b-41d4-a716-446655440000",
10 "task_prompt": "Summarize unread Gmail and post to Slack.",
11 "frequency": "daily",
12 "time": "09:00",
13 "timezone": "America/New_York",
14 },
15).json()
16 
17# 2. Add a webhook trigger — store the secret immediately
18trigger = requests.post(
19 f"https://coasty.ai/v1/schedules/{sched['id']}/triggers",
20 headers={"X-API-Key": "sk-coasty-test-..."},
21 json={"kind": "webhook"},
22).json()
23secret = trigger["webhook_secret"] # whsec_<64 hex> — store this
24 
25# 3. Sign + fire the webhook from any external system
26ts = int(time.time())
27body = b'{"event":"order.placed"}'
28sig = hmac.new(secret.encode(), f"{ts}.".encode() + body,
29 hashlib.sha256).hexdigest()
30requests.post(
31 trigger["webhook_url"],
32 headers={"Coasty-Signature": f"t={ts},v1={sig}"},
33 data=body,
34)
Schedules created via API show up in your /schedules dashboard automatically — same user_id, same view.
POST /v1/schedulesGET /v1/schedulesPATCH /v1/schedules/{id}DELETE /v1/schedules/{id}POST /v1/schedules/{id}/runPOST /v1/schedules/{id}/pausePOST /v1/schedules/{id}/resumeGET /v1/schedules/{id}/runsGET /v1/schedules/{id}/runs/{run_id}POST /v1/schedules/{id}/triggersDELETE /v1/schedules/{id}/triggers/{tid}POST /v1/triggers/webhook/{wh} ← unauth · HMACPOST /v1/triggers/email-mailbox

Screenshot in. Actions out.

No selectors. No DOM parsing. No brittle XPath. Just vision.

01

Send screenshot

Base64 PNG/JPEG + plain-language intent

02

AI reasons visually

Vision model identifies the target UI element

03

Execute actions

Typed primitives: click, type, scroll, press…

Vision-First

Works on any UI — web, desktop, mobile, VNC. No DOM access, no selectors, no agents.

Stateful Sessions

Multi-step trajectories. The model remembers what it tried, what worked, and what's next.

Two Engines

V3 for speed (3.5s/step, multi-action). V1 for precision (reflection, single-action).

Any Screen

Browser tabs, desktop apps, mobile emulators, VNC feeds — anything you can capture visually.

10 Action Types

click, double_click, type, scroll, drag, key_press, key_combo, wait, done, fail.

Any Language

Plain REST + JSON. Python, Node, Go, Ruby, PHP, Java, C#, or cURL from your terminal.

Per-request pricing. No subscription.

Deducted from your shared credit balance. Management endpoints always free.

EndpointCost
POST /predict5 cr
POST /sessions10 cr
POST /sessions/{id}/predict4 cr
POST /ground3 cr
POST /ocr3 cr
POST /parseFree
GET /models, /usage, /sessionsFree

Surcharges

Trajectory screenshot+2 cr each
HD image >1280×720+1 cr/image
V1 engine+3 cr/request
Custom system prompt+1 cr
Computer Use API

Send a screenshot, get actions back

The CUA API gives your code the ability to see and interact with any screen. Send a screenshot and a natural language instruction — receive structured mouse clicks, keyboard inputs, and scroll commands with exact coordinates.

Authentication

Every request needs an X-API-Key header. Sign up to create API keys. Credits are deducted per request from your shared balance.

header
X-API-Key: sk-coasty-live-your_key_here

How it Works

1Capture a screenshot of the target screen
2Send it with a natural language instruction
3Receive structured actions (click, type, scroll...)
4Execute the actions in your environment

Quick Start

Choose your language. The predict endpoint is the core of the API — everything else builds on it.

install
pip install requests
predict — single screenshot
import requests, base64

API_KEY = "sk-coasty-live-..."
img = base64.b64encode(open("screen.png", "rb").read()).decode()

r = requests.post(
    "https://coasty.ai/v1/predict",
    headers={"X-API-Key": API_KEY},
    json={
        "screenshot": img,
        "instruction": "Click the search bar and type 'hello'",
    },
)

for action in r.json()["actions"]:
    print(action["action_type"], action["params"])
sessions — multi-step tasks
# Create a session for multi-step tasks
s = requests.post(
    "https://coasty.ai/v1/sessions",
    headers={"X-API-Key": API_KEY},
    json={"cua_version": "v3", "screen_width": 1920, "screen_height": 1080},
).json()

session_id = s["session_id"]

# Send screenshots in a loop
while True:
    screenshot = capture_screenshot()  # your screenshot function
    r = requests.post(
        f"https://coasty.ai/v1/sessions/{session_id}/predict",
        headers={"X-API-Key": API_KEY},
        json={"screenshot": screenshot, "instruction": "Complete the form"},
    ).json()

    for action in r["actions"]:
        execute_action(action)  # your action executor

    if r["status"] in ("done", "fail"):
        break

Response Format

Every prediction returns structured actions with exact coordinates, a status signal, and token usage.

response
{
  "request_id": "req_abc123",
  "actions": [
    {
      "action_type": "click",
      "params": { "x": 512, "y": 340, "button": "left", "clicks": 1 }
    },
    {
      "action_type": "type_text",
      "params": { "text": "hello world" }
    }
  ],
  "reasoning": "I see a search bar at (512, 340)...",
  "status": "continue",
  "usage": {
    "input_tokens": 1523,
    "output_tokens": 245,
    "credits_charged": 5
  }
}

Action Types

clickMouse click at (x, y)
type_textType a string
key_pressPress a key (enter, tab...)
key_comboCombo (ctrl+c, cmd+v...)
scrollScroll at a position
dragDrag between two points
moveMove cursor
waitPause execution
doneTask completed
failTask impossible

Request Options

Only screenshot and instruction are required.

screenshotstringrequired
instructionstringrequired
cua_version"v3" | "v1"
screen_widthint
screen_heightint
max_actionsint (1-10)
trajectoryarray
system_promptstring
toolsstring[]

Predict Endpoints

Stateless prediction, sessions, and grounding utilities. All require the X-API-Key header.

Prediction
POST/v1/predict5 cr
POST/v1/sessions10 cr
POST/v1/sessions/{id}/predict4 cr
POST/v1/sessions/{id}/resetFree
DELETE/v1/sessions/{id}Free
Utilities
POST/v1/ground3 cr
POST/v1/ocr3 cr
POST/v1/parseFree
Management
GET/v1/modelsFree
GET/v1/usageFree
GET/v1/sessionsFree

Machines API

Provision a sandbox or production VM, then drive it with actions, terminal commands, browser automation, or file operations. Sandbox keys (sk-coasty-test-*) return mock VMs with no AWS billing.

Scopes
machines:readlist, get, screenshot
machines:writeprovision, start, stop, terminate
actions:execclick, type, scroll, browser_*
terminal:execshell command execution
files:readread, exists, list
files:writewrite, edit, append, delete
browser:executearbitrary JS in browser
snapshots:writecreate AMI snapshots
connection:readfetch SSH key + VNC password
Pricing
Provision (any provider)20 cr min
Agent run on managed VM10 cr/min
Raw VM-hour (Linux)50 cr/hr
Raw VM-hour (Windows)75 cr/hr
Idle VM (provisioned, unused)5 cr/hr
Snapshot create1 cr
Snapshot storage1 cr / 2 GB-mo
Egress (after first 10 GB/mo)1 cr/GB
Sandbox (sk-coasty-test-*)Free
TipUse a sk-coasty-test-* key during development — you get instant mock VMs (id mch_test_…), synthetic action results, and zero billing. The wire format matches production exactly, so you can swap to a live key and ship.

Provision & Lifecycle

Create a VM, list your fleet, and control start/stop/snapshot/terminate. Sandbox keys mock everything in-memory; live keys provision real EC2 / Azure instances.

provision a vm — python
import requests

# Provision a fresh Linux desktop VM. Sandbox keys (sk-coasty-test-*)
# return a mock machine instantly with no AWS billing.
r = requests.post(
    "https://coasty.ai/v1/machines",
    headers={
        "X-API-Key": "sk-coasty-live-...",
        "Idempotency-Key": "provision-bot-001",   # safe to retry
    },
    json={
        "display_name": "automation-bot",
        "os_type": "linux",
        "desktop_enabled": True,
    },
)
machine = r.json()["machine"]
print(machine["id"], machine["status"])
Lifecycle
GET/v1/machines
GET/v1/machines/{id}
POST/v1/machines/{id}/start
POST/v1/machines/{id}/stop
POST/v1/machines/{id}/snapshot
DELETE/v1/machines/{id}

Actions & Batches

Dispatch a single action, or chain up to 50 in one batch. Commands are validated against an explicit allowlist — typos return 422, never reach the VM.

single action — python
import requests

machine_id = "..."  # from provision response
r = requests.post(
    f"https://coasty.ai/v1/machines/{machine_id}/actions",
    headers={"X-API-Key": "sk-coasty-live-..."},
    json={
        "command": "click",
        "parameters": {"x": 512, "y": 340},
    },
)
result = r.json()
print(result["success"], result["duration_ms"], "ms")
Common Commands
clickactions:exec
typeactions:exec
key_pressactions:exec
key_comboactions:exec
scrollactions:exec
dragactions:exec
screenshotactions:exec
terminal_executeterminal:exec
file_readfiles:read
file_writefiles:write
browser_navigateactions:exec
browser_clickactions:exec
browser_executebrowser:execute
batch action — request body
POST /v1/machines/{id}/actions/batch
Content-Type: application/json
X-API-Key: sk-coasty-live-...

{
  "steps": [
    { "command": "browser_navigate",
      "parameters": { "url": "https://example.com/login" } },
    { "command": "browser_type",
      "parameters": { "selector": "#email", "text": "[email protected]" } },
    { "command": "browser_type",
      "parameters": { "selector": "#password", "text": "***" } },
    { "command": "browser_click",
      "parameters": { "selector": "button[type=submit]" } }
  ],
  "stop_on_error": true
}

Returns:
{
  "results": [...],         // one per step
  "completed_count": 4,
  "failed_count": 0,
  "aborted": false,
  "request_id": "req_..."
}

Browser, Terminal, Files

Typed convenience endpoints over /actions. Same dispatch path, ergonomic URL shapes, identical scope rules.

shell command — python
import requests

# Run a shell command (PowerShell on Windows, bash on Linux).
# Output is truncated VM-side to 5000 chars.
r = requests.post(
    f"https://coasty.ai/v1/machines/{machine_id}/terminal",
    headers={"X-API-Key": "sk-coasty-live-..."},
    json={
        "command": "uname -a && uptime",
        "timeout_ms": 10_000,
    },
)
print(r.json()["result"]["output"])
/browser/{op}
opennavigateclicktypedomclickablesstateinfoscrollclosescreenshotwaitlist-tabsopen-tabclose-tabswitch-tab

Body: { parameters: {…}, timeout_ms? }. browser_execute NOT here — use /actions with browser:execute.

/files/{op}
Read (files:read)
readexistslistlist-directorydownloadlist-downloads
Write (files:write)
writeeditappenddeletedelete-directory
/terminal
Body: { command, timeout_ms?, session_id?, cwd? }PowerShell on Windows, bash on Unix. Output capped at 5000 chars VM-side. Pass session_id to reuse a persistent shell across calls.Requires terminal:exec scope.

Machines Endpoints

Full reference. All require X-API-Key (or Authorization: Bearer) except /health.

Lifecycle
POST/v1/machines20 cr min
GET/v1/machinesFree
GET/v1/machines/{id}Free
DELETE/v1/machines/{id}Free
POST/v1/machines/{id}/startFree
POST/v1/machines/{id}/stopFree
POST/v1/machines/{id}/snapshot1 cr
Actions
POST/v1/machines/{id}/actionsFree
POST/v1/machines/{id}/actions/batchFree
POST/v1/machines/{id}/browser/{op}Free
POST/v1/machines/{id}/terminalFree
POST/v1/machines/{id}/files/{op}Free
Inspection
GET/v1/machines/{id}/screenshotFree
GET/v1/machines/{id}/connectionFree
GET/v1/machines/healthFree

Schedules API

Cron-fired agent runs, one-shot run_at jobs, plus three trigger kinds (webhook, email, chain). Schedules created via API show up in your /schedules dashboard automatically.

Scopes
schedules:readlist, get, runs, triggers
schedules:writecreate, update, delete, pause, run-now
triggers:writeadd/remove webhook, email, chain triggers
Pricing
Schedule create20 cr min
Per fire (agent run)10 cr/min
Webhook fire (routing)1 cr / 200
Email fire (routing)1 cr / 10
Chain trigger (no extra cost)Free
Pause / resume / list / runsFree
Sandbox (sk-coasty-test-*)Free
Frequency presets
every_15_minutes · every_30_minutes · hourly · every_6_hours · every_12_hours · daily · weekly · monthly · custom
Trigger kinds
webhook (HMAC) · email (inbound mailbox) · chain (fire when another schedule completes; max depth 5)
Run history
Each fire records {status, trigger, duration, credits, error, executed_at}. Cursor-paginated up to 100 retained per schedule.

Create & Lifecycle

Create a cron or one-shot schedule. Pause, resume, run-now, list runs, soft-delete. Idempotency-Key supported on POST.

create a schedule — python
import requests

# Daily 9:00 AM ET email summary, fired by the Coasty scheduler.
# Per-fire cost: 10 credits/min while the agent runs.
r = requests.post(
    "https://coasty.ai/v1/schedules",
    headers={
        "X-API-Key": "sk-coasty-live-...",
        "Idempotency-Key": "morning-briefing-001",
    },
    json={
        "name": "morning briefing",
        "machine_id": "550e8400-e29b-41d4-a716-446655440000",
        "task_prompt": "Summarize unread Gmail and post the top 5 to Slack.",
        "frequency": "daily",
        "time": "09:00",
        "timezone": "America/New_York",
    },
)
schedule = r.json()
print(schedule["id"], schedule["next_run_at"])
Frequency Presets
every_15_minutes*/15 * * * *
every_30_minutes*/30 * * * *
hourly0 * * * *
every_6_hours0 */6 * * *
every_12_hours0 */12 * * *
daily0 9 * * * (override with `time`)
weekly0 9 * * 1 (override `time`, `day_of_week`)
monthly0 9 1 * * (override `time`, `day_of_month`)
customsupply your own `cron` field
one-shot — fire once at a specific UTC time
POST /v1/schedules
Content-Type: application/json
X-API-Key: sk-coasty-live-...

{
  "name": "launch announcement",
  "machine_id": "550e8400-e29b-41d4-a716-446655440000",
  "task_prompt": "Post the launch tweet from the draft.",
  "run_at": "2099-01-01T17:00:00Z"
}

# Notes:
#   * `run_at` and `frequency` are mutually exclusive.
#   * Must be in the future (within last 60s tolerated).
#   * After firing once, the schedule auto-pauses with paused_reason='one_shot_complete'.
LifecycleSchedules are auto-paused after max_consecutive_failures (default 5) failed runs. Resume via POST /v1/schedules/{id}/resume. Insufficient credits at fire-time auto-pauses with reason insufficient_credits.

Triggers

Three trigger kinds. Webhook secrets are returned ONCE — store them on creation.

add a webhook trigger — python
# Add a webhook trigger — returns the signing secret ONCE.
r = requests.post(
    f"https://coasty.ai/v1/schedules/{schedule_id}/triggers",
    headers={"X-API-Key": "sk-coasty-live-..."},
    json={"kind": "webhook", "rate_limit_per_minute": 60},
)
trigger = r.json()
webhook_url    = trigger["webhook_url"]      # https://coasty.ai/v1/triggers/webhook/whk_...
webhook_secret = trigger["webhook_secret"]   # whsec_<64 hex>  — STORE THIS

# Save webhook_secret in your secrets manager. We hash + persist it; we
# cannot show it again. Lose it = generate a new trigger.
{ kind: "webhook" }
Returns webhook_url + webhook_secret (whsec_64hex). Sign every fire with HMAC-SHA256(secret, "{ts}.body") and send Coasty-Signature: t={ts},v1={sig}. Replay window 5 min. Idempotent on identical (id, body) within 60 s.
{ kind: "email" }
Provisions a unique <label>.<rand>@agents.coasty.ai address. Inbound emails fire the schedule. email_label must match ^[a-z0-9][a-z0-9._-]{0,32}[a-z0-9]$.
{ kind: "chain" }
Fire this schedule when source_schedule_id completes. Events: on_complete · on_failure · on_any.Max chain depth: 5.
Trigger Endpoints
GET/v1/schedules/{id}/triggers
POST/v1/schedules/{id}/triggers
DELETE/v1/schedules/{id}/triggers/{trigger_id}
POST/v1/triggers/email-mailbox

Public Webhook Fire

POST /v1/triggers/webhook/{webhook_id} — UNAUTHENTICATED but HMAC-verified. Hit by Stripe, Linear, n8n, anything that can sign a request.

sign + fire a webhook — python
# Customer-side webhook signing — produces a Coasty-Signature header
# the public /v1/triggers/webhook/{id} endpoint accepts.
import hmac, hashlib, time

def sign_coasty_webhook(secret: str, body: bytes) -> dict:
    ts = int(time.time())
    signed_payload = f"{ts}.".encode("utf-8") + body
    sig = hmac.new(secret.encode("utf-8"), signed_payload, hashlib.sha256).hexdigest()
    return {"Coasty-Signature": f"t={ts},v1={sig}"}

# Fire the webhook from your own app:
import requests
body = b'{"event":"order.placed","order_id":"123"}'
headers = {**sign_coasty_webhook(webhook_secret, body), "Content-Type": "application/json"}
requests.post(webhook_url, data=body, headers=headers)
header format
Coasty-Signature: t=<unix_ts>,v1=<hmac_sha256_hex>

# t        = current unix timestamp (seconds)
# v1       = lowercase hex HMAC-SHA256(webhook_secret, "<t>.<body>")
#            (period as separator; raw body bytes; no newline)
# replay   = signatures > 5 min stale are rejected
# dedup    = identical (webhook_id, body) within 60 s returns deduplicated=true
# body cap = 1 MB (413 if exceeded)
example response
HTTP/1.1 200 OK
Content-Type: application/json
X-Coasty-Request-Id: req_...
X-Coasty-Webhook-Deduplicated: false

{
  "received": true,
  "schedule_id": "550e8400-...",
  "run_id": "550e8400-...",
  "deduplicated": false,
  "message": "Schedule fire dispatched.",
  "request_id": "req_..."
}
SecurityTreat webhook_secret like a password — it grants the ability to fire your schedule. Coasty stores it server-side and uses it to verify every inbound signature. If leaked: delete the trigger and re-create to rotate.

Schedules Endpoints

Full reference. Public webhook fire endpoint is the only one without auth (it uses HMAC-signed Coasty-Signature instead).

Lifecycle
POST/v1/schedules20 cr min
GET/v1/schedulesFree
GET/v1/schedules/{id}Free
PATCH/v1/schedules/{id}Free
DELETE/v1/schedules/{id}Free
POST/v1/schedules/{id}/pauseFree
POST/v1/schedules/{id}/resumeFree
POST/v1/schedules/{id}/run10 cr/min
History
GET/v1/schedules/{id}/runsFree
GET/v1/schedules/{id}/runs/{run_id}Free
Triggers
GET/v1/schedules/{id}/triggersFree
POST/v1/schedules/{id}/triggersFree
DELETE/v1/schedules/{id}/triggers/{trigger_id}Free
POST/v1/triggers/email-mailboxFree
POST/v1/triggers/webhook/{webhook_id}1 cr / 200

MCP Server

Drive Coasty from any MCP-capable client — Claude Desktop, Claude Code, Cursor, Windsurf, VS Code Copilot. One install, every Coasty tool available.

What is MCP?

MCP (Model Context Protocol) is the open standard, designed by Anthropic and adopted across the agent ecosystem, that lets LLM hosts plug into external tools and data. Coasty's MCP server is a thin wrapper over the /v1 API — same scopes, same rate limits, same billing. It runs locally via npx; your API key never touches a Coasty MCP relay.

Package
npm i -g @coasty/mcp

Or just point your MCP host at npx -y @coasty/mcp — zero install needed. Set COASTY_API_KEY in the host config and you're running. Sandbox keys (sk-coasty-test-*) work for free.

What you can do from your editor
Predict
Hand the agent a screenshot, get back a sequence of typed actions (click, type, scroll, ...) with exact coordinates.
Drive a VM
Provision a sandbox VM, run terminal commands, navigate a browser, edit files — all from chat.
Schedule a job
Set up a cron job, attach a webhook trigger, hand the secret to your AI to wire into Stripe / Linear / anything.

Install in your MCP host

Pick your client. Configs are checked into the @coasty/mcp test suite — copying any of these blocks verbatim produces a working install.

Claude Desktop — claude_desktop_config.json
// macOS:    ~/Library/Application Support/Claude/claude_desktop_config.json
// Windows:  %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "coasty": {
      "command": "npx",
      "args": ["-y", "@coasty/mcp"],
      "env": { "COASTY_API_KEY": "sk-coasty-test-..." }
    }
  }
}

// Restart Claude Desktop. Coasty tools appear under the 🛠 icon.
Claude Code (CLI)
claude mcp add coasty \
  --env COASTY_API_KEY=sk-coasty-test-... \
  -- npx -y @coasty/mcp

# Verify
claude mcp list
# coasty                     ✓ connected   (24 tools, 2 prompts)
Cursor — .cursor/mcp.json (project) or ~/.cursor/mcp.json (global)
{
  "mcpServers": {
    "coasty": {
      "command": "npx",
      "args": ["-y", "@coasty/mcp"],
      "env": { "COASTY_API_KEY": "sk-coasty-test-..." }
    }
  }
}

// Cursor → Settings → MCP shows a green dot when reachable.
Windsurf — ~/.codeium/windsurf/mcp_config.json
{
  "mcpServers": {
    "coasty": {
      "command": "npx",
      "args": ["-y", "@coasty/mcp"],
      "env": { "COASTY_API_KEY": "sk-coasty-test-..." }
    }
  }
}
VS Code Copilot (Agent mode) — .vscode/mcp.json
// VS Code uses "servers" (NOT "mcpServers"). Tools only appear in
// Agent mode — type # in the chat to autocomplete tool names.
{
  "servers": {
    "coasty": {
      "command": "npx",
      "args": ["-y", "@coasty/mcp"],
      "env": { "COASTY_API_KEY": "sk-coasty-test-..." }
    }
  }
}
TipUse a sk-coasty-test-* key while you're iterating — everything works (provision, schedule, run) but no real EC2 / Azure / credit billing. Swap in sk-coasty-live-* when you're ready to ship.

Tools the MCP server exposes

24 tools across Predict, Machines, Schedules, and Account. All carry MCP annotations (readOnly / destructive / idempotent) so well-behaved hosts confirm before destructive operations.

Predict
coasty_predictScreenshot + goal → list of actions
coasty_groundElement description → (x, y) coords
coasty_ocrScreenshot → text + bounding boxes
coasty_parsepyautogui code → structured actions (free)
Machines
coasty_list_machinesRead-only — your VMs
coasty_get_machineRead-only — one VM
coasty_take_machine_screenshotRead-only — current desktop image
coasty_provision_machineCreate new VM (idempotent w/ key)
coasty_terminate_machineDestructive — irreversible
coasty_start_machineResume a stopped VM
coasty_stop_machinePause running VM (preserves state)
coasty_execute_machine_actionDispatch click / type / scroll / browser_* / file_* / etc.
coasty_run_terminal_commandShell exec on VM (terminal:exec scope)
Schedules
coasty_list_schedulesRead-only
coasty_get_scheduleRead-only
coasty_list_schedule_runsCursor-paginated history
coasty_create_scheduleCron, run-once, or custom — appears in dashboard
coasty_update_schedulePATCH (any field)
coasty_delete_scheduleDestructive — soft-delete
coasty_run_schedule_nowManual fire (idempotent w/ key)
coasty_pause_scheduleDisable future fires
coasty_resume_scheduleRe-enable
coasty_add_triggerWebhook / email / chain (HMAC secret returned ONCE)
coasty_remove_triggerDestructive
Account
coasty_get_creditsRead-only — balance + tier + period usage
Prompts
start_automation_session — pre-fill a chat that picks a VM, screenshots, predicts, and executes toward a goal.
debug_failed_run — investigate why a schedule has been failing; proposes concrete fixes.
Annotations
Every tool advertises readOnlyHint, destructiveHint, idempotentHint, and openWorldHint so a well-configured host can auto-approve safe reads and require explicit consent for destructive ops.

Error Handling

All errors return a JSON body with error.code, error.message, error.type, and error.request_id fields.

400INVALID_MACHINE_IDPath id is not a UUID or mch_test_<hex>
400INVALID_IDEMPOTENCY_KEYIdempotency-Key has bad chars or > 128 chars
400UNKNOWN_BROWSER_OPUnknown {op} in /browser/{op}
400UNKNOWN_FILE_OPUnknown {op} in /files/{op}
401INVALID_API_KEYMissing or invalid X-API-Key / Bearer token
402INSUFFICIENT_CREDITSBalance below required amount (provision needs ≥ 20 cr)
403INSUFFICIENT_SCOPEAPI key lacks the required scope for this op
404NOT_FOUNDMachine/session not found OR not owned by your key
409INVALID_STATEAction requires status='running'; lifecycle has illegal transition
422IDEMPOTENCY_KEY_REUSEDSame Idempotency-Key sent with a different request body
422VALIDATION_ERRORBody fails Pydantic — unknown field, wrong type, oversize, bad command
429RATE_LIMIT_EXCEEDEDToo many requests — see Retry-After header
429TEST_MACHINE_LIMITSandbox keys are capped at 5 mock VMs
502SCREENSHOT_FAILEDScreenshot dispatch reached the VM but capture errored
503DB_UNAVAILABLEBackend cannot reach Supabase
504UPSTREAM_TIMEOUTProvision proxy timed out (try Idempotency-Key + retry)
400INVALID_SCHEDULE_IDschedule_id is not a UUID or sch_test_<hex>
400INVALID_TRIGGER_IDtrigger_id is not 'trg_<hex>'
400INVALID_RUN_IDrun_id contains non-allowlisted chars
400INVALID_LIMITlimit must be 1..200
400INVALID_STATUS_FILTERUnknown ?status= value on /runs
400EMPTY_UPDATEPATCH body has no fields
401INVALID_SIGNATUREMissing/malformed/stale/tampered Coasty-Signature
404SOURCE_SCHEDULE_NOT_FOUNDChain trigger source not owned by your key
404RUN_NOT_FOUNDRun id not in this schedule's history
410WEBHOOK_DISABLEDWebhook trigger has been disabled by the owner
429TEST_SCHEDULE_LIMITSandbox keys are capped at 10 mock schedules
429SCHEDULE_LIMIT_REACHEDPer-tier slot limit (free:3 / pro:10 / enterprise:50)

Ship your first click in minutes.

Free account, free keys, free credits to start. No card required.

Coasty - #1 Computer-Use AI Agent | AI Employee for Desktop & Browser Automation