Skip to content

AI agents & API

Local HTTP API

The Accovod local HTTP API on macOS and Windows — address and token from control.json, the /v1/rpc endpoint, responses, error codes, curl, PowerShell and Python examples.

The MCP server runs on this API, and you can call it directly too — from Python, Node, n8n, Postman or anything that speaks HTTP.

Once the API is on (how to turn it on), Accovod starts a server on 127.0.0.1 and writes its details to a file:

~/Library/Application Support/Accovod/control.json
{
"app": "Accovod",
"platform": "macos",
"apiVersion": "1.0",
"port": 25252,
"token": "8f3c…",
"baseUrl": "http://127.0.0.1:25252"
}
  • The port is 25252 when it’s free. Reading baseUrl from the file is more reliable than hard-coding the address.
  • The file is deleted when Accovod quits. No file means the app isn’t running or the API is off.
  • platform is macos or windows.
  • Rotate the token with Automation → Regenerate token on macOS or the New token button on Windows.

There’s one endpoint — POST /v1/rpc — with the method and parameters in the body:

Terminal window
CONTROL=~/Library/Application\ Support/Accovod/control.json
BASE=$(jq -r .baseUrl "$CONTROL")
TOKEN=$(jq -r .token "$CONTROL")
curl -s "$BASE/v1/rpc" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"method":"profiles.list","params":{}}'

GET /v1/health answers without a token — use it to check whether the app is running.

Every response uses the same envelope:

{ "ok": true, "result": { … } }
{ "ok": false, "error": { "code": "PROFILE_NOT_FOUND", "message": "…", "hint": "…" } }

hint says what to fix in the request. An optional id in the request is echoed back.

  • profileId is the only reliable profile identifier. Take it from profiles.list and pass it to every page.* method. index changes when the list is reordered.
  • Start with app.status. It reports the profile mode (all or activeOnly), the active group and whether the agent is stopped.
  • Elements come from page.snapshot. It returns interactive elements with a ready-made target object. Pass it to page.click and page.fill as is. Take a new snapshot after navigating.
  • Retries are safe. profiles.create, profiles.createMany and profiles.importMany require an idempotencyKey: a retry with the same key returns what was already created instead of a duplicate.
  • Deletion needs confirm: true. Without it, profiles.delete and sessions.delete delete nothing and report what would have been deleted.
  • Long work can run through operations.start, with the result fetched by operations.get — useful when your client times out long calls.
Code HTTP Meaning
UNAUTHORIZED 401 Missing or wrong token.
BROWSER_ORIGIN_BLOCKED 403 The request came from a page in a browser — those are refused.
AGENT_STOPPED 409 The person pressed Stop. Everything except app.status is refused until Resume.
PROFILE_NOT_FOUND 404 No such profileId in the open group.
PROFILE_NOT_LIVE 409 The profile has no open tab — in activeOnly mode call profiles.open first.
REVISION_MISMATCH 409 The profile changed since you read it. Nothing was written — read it again and retry.
PROFILE_LIMIT_REACHED 409 The cloud group has hit the plan’s limit.
SESSION_LOADING 409 macOS: the group is still loading from the cloud. Requests wait for it up to two minutes; after that, retry in a few seconds.
SESSION_CHANGED 409 While the group was opening, the person or another request opened a different one.
CLOUD_UNAVAILABLE 502 Accovod Cloud didn’t answer. Check the connection and retry.
TARGET_NOT_FOUND / AMBIGUOUS_TARGET 404 / 409 No element, or several, matched — nothing was clicked.
ELEMENT_OCCLUDED 409 A banner or dialog covers the element — the message names it.
CONFIRMATION_REQUIRED 400 Deletion without confirm: true.

The API contract on Windows is the same: the same methods, parameters, responses and error codes. Behavior differs only where the app itself works differently.

  • Engines. A profile’s engine is chrome (the built-in Chromium) or edge (Microsoft Edge WebView2). browser for a new profile is chrome, edge, firefox, mobile, auto or native.
  • Profile mode profileMode can also be onDemand — a profile loads when first opened and then stays in memory (Load When Selected in settings). In the all and onDemand modes page.navigate loads a profile in the background without switching the screen.
  • Changing the protection mode with settings.set is saved at once but applies after Accovod restarts: the answer has restartRequired: true.
  • Page dialogs. While a site shows alert, confirm or prompt, the page is paused. Calls answer DIALOG_OPEN with the dialog text, and page.dialog (accept, promptText) answers it. You still see the dialog as usual.
  • A profile not on screen. The browser doesn’t deliver mouse hover and wheel events to a hidden tab, so there page.hover and page.scroll fall back to script and say so (trusted: false). page.select always picks the option by script. Clicks, keys and typing are real in every case, and profiles are filled in parallel.
  • Deleting a profile. Cookies are erased at once; the profile folder with cache and LocalStorage goes when Accovod closes (storageRemoved: false with a note).
  • Deleting a group keeps its backups in cef\sessions — the way back after a mistake.
  • page.upload takes files from Downloads, Desktop, Documents, Pictures, Videos and Music, and the same folders in OneDrive, with no extra setup. Add other folders to the MCP server’s ACCOVOD_UPLOAD_ROOTS environment variable, separated by ;.
  • No DevTools port is opened: cdp.available in app.status is false.

Extra error codes on Windows:

Code HTTP Meaning
DIALOG_OPEN 409 The page shows an alert, confirm or prompt. Answer it with page.dialog.
NO_DIALOG 409 page.dialog was called, but no dialog is open.
TARGET_MISMATCH 400 The ref points to the same element, but role, name or within don’t fit it — the request is wrong, not the page.
NOT_EDITABLE / NOT_FOCUSABLE 400 / 409 page.fill got an element that isn’t a text field or doesn’t take focus. Nothing was typed.
MULTIPLE_CONDITIONS 400 page.waitFor got more than one condition.
IDEMPOTENCY_CONFLICT 409 The same idempotencyKey came with different parameters.
BROWSER_TIMEOUT 504 The profile’s browser didn’t answer in time.

When a page fails to load — a dead proxy, no DNS — page.navigate and page.reload answer loaded: false with the network code in netError, for example ERR_PROXY_CONNECTION_FAILED.

Every method and its main parameters are in the tools reference. MCP tool and API method names map simply: profiles_list ↔ profiles.list, page_wait_for ↔ page.waitFor.