Skip to content

Automation (MCP) API ​

The /mcp endpoint lets MCP clients - Claude and other assistants that speak the Model Context Protocol - drive your account. Ask in plain language ("clone my staging pod", "how much credit is left?") and the client calls the matching tool.

Authentication ​

MCP is API key only. A login token will not work here.

http
Authorization: Bearer mck_1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f809

Create a key, scope it to exactly what the assistant should be allowed to touch, and optionally IP-bind it - see API keys. The key's permissions decide which tools it can call, and a key only ever sees the tools it is allowed to use.

Protocol ​

/mcp speaks JSON-RPC 2.0 over plain HTTP POST. It is stateless (no sessions, no streaming), so every call is a self-contained request to:

POST https://cloud-api.microapps.io/mcp
MethodWhat it does
initializeHandshake; the client announces itself and gets server info back
pingLiveness check; returns an empty result
tools/listList the tools this key may call
tools/callRun a tool, with params: { name, arguments }

Most MCP clients only need the URL and your API key; they handle the JSON-RPC plumbing for you.

A few details that matter if you are writing the client yourself:

  • GET and DELETE on /mcp return 405. There is no SSE stream and no session to terminate.
  • A notification (a request with no id) is acknowledged with 202 and an empty body.
  • The protocol version defaults to 2025-03-26. Send your own in initialize and it is echoed back.
  • Everything else answers 200, including failures - the JSON-RPC error object carries the problem, not the HTTP status.
json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "capabilities": { "tools": {} },
    "serverInfo": { "name": "cloud-api", "version": "1.0.0" }
  }
}

Tools ​

Each tool is gated by the same permission as its REST equivalent, so a key can never do more through MCP than it could through the API. Tools the key cannot use do not show up in tools/list, and calling one anyway comes back as a tool error rather than a silent no-op.

ToolDoesPermission
list_podsList your podspods:read
get_podDescribe one podpods:read
pod_actionStart, stop, or restart a pod (action: start / stop / restart)pods:update
clone_podClone a pod into a new onepods:create
list_snapshotsList a pod's snapshotssnapshots:read
create_snapshotTake a snapshotsnapshots:create
list_backupsList a pod's backupsbackups:read
list_account_backupsList every backup on the account, including ones whose pod was deletedbackups:read
create_backupTake a backupbackups:create
list_domainsList your domainsdomains:read
list_networksList your networksnetworks:read
get_accountRead credit, limits, and contact detailsany key
create_announcementPublish a platform-wide noticeoperator only

get_pod, pod_action, clone_pod, list_snapshots, create_snapshot, list_backups and create_backup take a podId; pod_action takes action as well. list_pods, list_account_backups, list_domains, list_networks and get_account take no arguments. create_announcement is an operator tool and never appears in a customer key's tools/list - no API key can hold the account permissions it requires.

Tools that change things (pod_action, clone_pod, create_snapshot, create_backup) obey the same $3 credit minimum as the API and show up in your activity log, just like a console click. Read-only tools do neither.

Example: list tools ​

bash
curl -X POST https://cloud-api.microapps.io/mcp \
  -H "Authorization: Bearer $MICROAPPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Example: call a tool ​

bash
curl -X POST https://cloud-api.microapps.io/mcp \
  -H "Authorization: Bearer $MICROAPPS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "pod_action",
      "arguments": { "podId": "6a4d5b83b7006ccae6391810", "action": "restart" }
    }
  }'

A tool result is MCP content, with the payload as JSON inside a text block:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{ "type": "text", "text": "{\n  \"message\": \"Action restart executed\"\n}" }],
    "isError": false
  }
}

Errors ​

Two kinds, and they look different.

Tool errors are a normal result with isError: true and the explanation in the text block. This is what you get for a missing permission, a pod that is not yours, or too little credit:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [{ "type": "text", "text": "Error: insufficient credit. You need at least $3 on your account to proceed." }],
    "isError": true
  }
}

Protocol errors are a JSON-RPC error object, still over HTTP 200:

CodeWhen
-32700The body was not valid JSON
-32601Unknown method
-32602Malformed params, or an unknown tool name
-32603The result could not be encoded

See also ​

Built for the long tail.