AI-агенты и API
Локальный HTTP API
Локальный HTTP API Accovod на macOS и Windows — адрес и токен из control.json, точка /v1/rpc, формат ответов, коды ошибок, примеры на curl, PowerShell и Python.
Через этот API работает MCP-сервер, и к нему же можно обращаться напрямую — из Python, Node, n8n, Postman или любой программы, которая умеет HTTP.
Адрес и токен
Заголовок раздела «Адрес и токен»Когда API включён (как включить), Accovod запускает сервер на 127.0.0.1 и записывает параметры в файл:
~/Library/Application Support/Accovod/control.json%APPDATA%\Accovod\control.json{ "app": "Accovod", "platform": "macos", "apiVersion": "1.0", "port": 25252, "token": "8f3c…", "baseUrl": "http://127.0.0.1:25252"}- Порт — 25252, если он свободен. Надёжнее читать
baseUrlиз файла, чем хардкодить адрес. - Файл удаляется, когда Accovod закрывается. Нет файла — приложение не запущено или API выключен.
- Поле
platform—macosилиwindows. - Токен меняется через Automation → Regenerate token на macOS или кнопкой New token на Windows.
Как вызывать
Заголовок раздела «Как вызывать»Одна точка входа — POST /v1/rpc, в теле указывается метод и параметры:
CONTROL=~/Library/Application\ Support/Accovod/control.jsonBASE=$(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":{}}'$control = Get-Content "$env:APPDATA\Accovod\control.json" | ConvertFrom-Json
Invoke-RestMethod -Method Post -Uri "$($control.baseUrl)/v1/rpc" ` -Headers @{ Authorization = "Bearer $($control.token)" } ` -ContentType "application/json" ` -Body '{"method":"profiles.list","params":{}}'import json, os, pathlib, sys, urllib.request
# control.json: на Windows — в %APPDATA%, на macOS — в Application Supportif sys.platform == "win32": path = pathlib.Path(os.environ["APPDATA"], "Accovod", "control.json")else: path = pathlib.Path("~/Library/Application Support/Accovod/control.json").expanduser()control = json.loads(path.read_text())
def call(method, **params): req = urllib.request.Request( control["baseUrl"] + "/v1/rpc", data=json.dumps({"method": method, "params": params}).encode(), headers={"Authorization": f"Bearer {control['token']}", "Content-Type": "application/json"}) reply = json.load(urllib.request.urlopen(req)) if not reply["ok"]: raise RuntimeError(reply["error"]) return reply["result"]
for p in call("profiles.list")["profiles"]: print(p["name"], p["url"])GET /v1/health отвечает без токена — так можно проверить, запущено ли приложение.
Формат ответа
Заголовок раздела «Формат ответа»Все ответы в одном конверте:
{ "ok": true, "result": { … } }{ "ok": false, "error": { "code": "PROFILE_NOT_FOUND", "message": "…", "hint": "…" } }hint подсказывает, что поправить в запросе. Необязательное поле id из запроса возвращается в ответе.
Главные правила
Заголовок раздела «Главные правила»profileId— единственный надёжный идентификатор профиля. Берите его изprofiles.listи передавайте во все методыpage.*. Полеindexменяется при сортировке.- Сначала
app.status. Он показывает режим загрузки профилей (allилиactiveOnly), активную группу и остановлен ли агент. - Элементы — через
page.snapshot. Он возвращает список интерактивных элементов с готовым объектомtarget. Передавайте его вpage.clickиpage.fillцеликом. После перехода на другую страницу сделайте новый снимок. - Повторы безопасны.
profiles.create,profiles.createMany,profiles.importManyтребуютidempotencyKey: повтор с тем же ключом вернёт уже созданное, а не создаст дубль. - Удаление — только с
confirm: true. Без негоprofiles.deleteиsessions.deleteничего не удаляют и отвечают, что именно было бы удалено. - Долгие операции можно запускать через
operations.startи спрашивать результат черезoperations.get— это спасает при таймаутах клиента.
Частые ошибки
Заголовок раздела «Частые ошибки»| Код | HTTP | Что значит |
|---|---|---|
UNAUTHORIZED |
401 | Нет токена или токен неверный. |
BROWSER_ORIGIN_BLOCKED |
403 | Запрос пришёл со страницы в браузере — такие отклоняются. |
AGENT_STOPPED |
409 | Пользователь нажал Stop. Всё, кроме app.status, отклоняется до Resume. |
PROFILE_NOT_FOUND |
404 | Такого profileId нет в открытой группе. |
PROFILE_NOT_LIVE |
409 | У профиля нет открытой вкладки — в режиме activeOnly сначала вызовите profiles.open. |
REVISION_MISMATCH |
409 | Профиль изменили, пока вы его читали. Ничего не записано — перечитайте и повторите. |
PROFILE_LIMIT_REACHED |
409 | В облачной группе закончился лимит тарифа. |
SESSION_LOADING |
409 | macOS: группа ещё загружается из облака. Запросы ждут её до двух минут, после — повторите через несколько секунд. |
SESSION_CHANGED |
409 | Пока группа открывалась, человек или другой запрос открыл другую. |
CLOUD_UNAVAILABLE |
502 | Облако Accovod не ответило. Проверьте интернет и повторите запрос. |
TARGET_NOT_FOUND / AMBIGUOUS_TARGET |
404 / 409 | Элемент не найден или подходят несколько — ничего не нажато. |
ELEMENT_OCCLUDED |
409 | Элемент перекрыт баннером или окном — в сообщении указано, чем именно. |
CONFIRMATION_REQUIRED |
400 | Удаление без confirm: true. |
Особенности Windows
Заголовок раздела «Особенности Windows»Контракт API на Windows тот же: те же методы, параметры, ответы и коды ошибок. Отличается поведение там, где устроена по-другому сама программа.
- Движки.
engineу профиля —chrome(встроенный Chromium) илиedge(Microsoft Edge WebView2).browserпри создании профиля —chrome,edge,firefox,mobile,autoилиnative. - Режим профилей
profileModeбывает ещё иonDemand— профиль загружается при первом открытии и дальше остаётся в памяти (в настройках это Load When Selected). В режимахallиonDemandpage.navigateзагружает профиль в фоне, не переключая экран. - Смена режима защиты через
settings.setсохраняется сразу, а применяется после перезапуска Accovod: в ответеrestartRequired: true. - Диалоги страницы. Пока сайт показывает
alert,confirmилиprompt, страница на паузе. Вызовы отвечаютDIALOG_OPENс текстом диалога, а ответить на него можно методомpage.dialog(accept,promptText). Вы при этом видите диалог как обычно. - Профиль не на экране. Наведение и колёсико мыши браузер не доставляет в скрытую вкладку, поэтому там
page.hoverиpage.scrollработают скриптом и сообщают об этом (trusted: false).page.selectвсегда выбирает вариант скриптом. Клики, клавиши и ввод текста — настоящие в любом случае, и профили заполняются параллельно. - Удаление профиля. Cookies стираются сразу, а папка профиля с кэшем и LocalStorage — при закрытии Accovod (
storageRemoved: falseс пояснением). - Удаление группы оставляет её резервные копии в
cef\sessions— по ним можно восстановить группу после ошибки. page.uploadбез настройки берёт файлы из папок «Загрузки», «Рабочий стол», «Документы», «Изображения», «Видео», «Музыка» и таких же папок в OneDrive. Другие папки добавляются в переменную окруженияACCOVOD_UPLOAD_ROOTSMCP-сервера через;.- Порт DevTools не открывается:
cdp.availableвapp.status—false.
Дополнительные коды ошибок на Windows:
| Код | HTTP | Что значит |
|---|---|---|
DIALOG_OPEN |
409 | На странице открыт alert, confirm или prompt. Ответьте на него через page.dialog. |
NO_DIALOG |
409 | page.dialog вызван, а диалога нет. |
TARGET_MISMATCH |
400 | ref указывает на тот же элемент, но role, name или within ему не подходят — ошибка в запросе, а не на странице. |
NOT_EDITABLE / NOT_FOCUSABLE |
400 / 409 | page.fill получил элемент, который не является полем ввода или не принимает фокус. Ничего не введено. |
MULTIPLE_CONDITIONS |
400 | В page.waitFor передано больше одного условия. |
IDEMPOTENCY_CONFLICT |
409 | Тот же idempotencyKey пришёл с другими параметрами. |
BROWSER_TIMEOUT |
504 | Браузер профиля не ответил вовремя. |
Если страница не загрузилась — прокси не отвечает, нет DNS, — page.navigate и page.reload отвечают loaded: false и кодом сети в netError, например ERR_PROXY_CONNECTION_FAILED.
Все методы и их основные параметры — в справочнике инструментов. Имя MCP-инструмента и метода API связаны просто: profiles_list ↔ profiles.list, page_wait_for ↔ page.waitFor.