Afina MCP Server#
The Afina MCP server connects an AI agent to the local Afina HTTP API through the standard Model Context Protocol. The agent gets not a "chat with hints", but a set of real tools: reading accounts and scripts, launching browsers, checking proxies, working with RPA modules, task groups, logs, cookies, and migration from other antidetect browsers.
- Transport:
stdio - Package:
npx -y afina-mcp - Afina API:
http://localhost:50778orhttp://127.0.0.1:50778 - Authentication: the
AFINA_API_KEYenvironment variable - Live check:
afina-mcpreturnsTools: 92, resources: 5
How Afina MCP works#
Afina MCP Server is a stdio server for AI clients that translates MCP calls into HTTP requests to the local Afina API. When Afina is running, the desktop app starts a local HTTP server on port 50778; if the port is busy, Afina tries the next ports in the range.
The AI client does not access the Afina database directly and does not edit profile files manually. It calls an MCP tool, afina-mcp validates the arguments, sends an HTTP request to Afina with x-api-key, receives the response, and returns it to the agent in MCP format.
afina-mcp is a separate npm package. It does not store Afina session state and lives only as long as the MCP client keeps it running.
Prerequisites#
Before connecting, check your local environment.
| What | How to check | Why it is needed |
|---|---|---|
| Afina is running | the app is open locally | Starts the HTTP API |
| Afina API key | Settings → General → API key | Passed as AFINA_API_KEY |
| Node.js 18+ | node --version | Runs npx |
| npx | npx --version | Downloads afina-mcp |
| Claude Code | claude --version | MCP client for the connection |
Without a valid AFINA_API_KEY, most Afina /api/* endpoints will return 401 Unauthorized or close the connection. The MCP server also will not start correctly without this variable.
Connecting through CLI#
Afina MCP connects to any AI agent in the same way: the client starts npx -y afina-mcp as a local process with the stdio transport and gets access to all 92 Afina tools through the AFINA_API_KEY variable. The only difference between clients is where the config is stored.
Claude Code
For the current project (recommended):
For all projects of the current user:
Check the connection:
Codex CLI and other CLI clients
CLI clients without a built-in mcp add command connect MCP through a config file. For Codex CLI, this is ~/.codex/config.yaml:
For Gemini CLI, use ~/.gemini/settings.json or .gemini/settings.json in the project (the JSON format is shown in the next section).
Connecting through an agent#
Do not want to enter commands manually? Copy the prompt below, replace [INSERT_KEY] with your API key, and send it to the agent - it will complete all steps by itself.
If you use --scope project, add .mcp.json to .gitignore. This file stores AFINA_API_KEY, so it must not be committed to the repository. Similarly, exclude any config file that contains the key from git.
After connecting, restart the client. MCP tools are loaded when a new session starts - the server may be added correctly, but the tools will not appear until restart.
Configuring config files#
If the MCP client expects a JSON config, use the standard stdio format. It is the same for all clients that support the MCP specification.
| Client | Config path |
|---|---|
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Cursor | .cursor/mcp.json in the project root or ~/.cursor/mcp.json globally |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Gemini CLI | .gemini/settings.json in the project or ~/.gemini/settings.json globally |
| Cline | MCP settings in the VS Code extension GUI |
| Continue | .continue/config.json in the project |
The "type": "stdio" field can be optional - some clients detect the transport automatically when command is set. If the client does not recognize the config, check the documentation for the specific version.
Config files that contain AFINA_API_KEY should be excluded from version control. For team workflows, store the key in a secrets manager or CI/CD environment variables.
How the agent calls tools#
When you write "show me the list of accounts" to the agent, Claude Code does not run shell commands directly. It sends a JSON-RPC call to stdin of the afina-mcp process.
afina-mcp turns this into an HTTP request to local Afina, adds x-api-key, receives a JSON response, and returns it to the agent.
For direct diagnostics without restarting Claude Code, you can run tools/list manually.
The live tools/list response confirms 92 tools and 5 resources. If your local list differs, your current afina-mcp has priority over this page.
Available tools#
Below are the tool groups confirmed by the live tools/list. Tool and parameter names remain in English because they are part of the executable API.
Accounts and profiles#
| Tool | Required parameters | What it does |
|---|---|---|
list_accounts | - | Returns accounts with groupId, tagId, isRunning filters |
resolve_account | query | Resolves a UUID, name, numberId, or DB id into a full account |
get_account | accountId | Reads one account by UUID |
create_account | - | Creates a persistent profile with fingerprint, proxy, tags, groups, settings |
create_one_time_profile | - | Creates a disposable profile, launches the browser, and deletes it after stop |
update_account | - | PATCH update for an account by id or accountId |
delete_account | accountId | Soft-deletes an account |
hard_delete_account | - | Permanently deletes by id, ids, accountId, or accountIds |
If the user asks for a "temporary", "single-use", "disposable", or "one-time" profile, the agent must call create_one_time_profile, not create_account. Regular create_account creates a persistent account.
Browser session and page#
| Tool | Required parameters | What it does |
|---|---|---|
start_browser | profileId | Launches the browser and returns wsEndpoint |
stop_browser | profileId | Closes the browser through CDP |
eval_in_browser | profileId, code | Runs JavaScript in the current tab |
find_clickable | profileId, text | Finds a clickable element by text |
find_input | profileId, query | Finds an input field |
get_current_url | profileId | Returns the active tab URL |
get_page_text | profileId | Reads page text, supports selector and maxChars |
take_screenshot | profileId | Takes a screenshot of the current tab |
This group gives the agent a "one-off AI session" mode: launch an account, open the required page, read text, take a screenshot, find a button or field, and close the browser without writing an RPA script.
Cookies#
| Tool | Required parameters | What it does |
|---|---|---|
set_cookies | accountId, cookies | Queues cookies for import into an account |
export_cookies | - | Exports cookies by id, ids, accountId, or accountIds |
set_cookies is useful for moving authorized sessions. If the account is not running, cookies will be applied on the next browser start.
RPA scripts#
| Tool | Required parameters | What it does |
|---|---|---|
list_scripts | - | Returns the list of scripts |
get_script | id | Reads the full structure of one script |
create_script | name, settings | Creates an RPA script |
update_script | id | Updates a script |
run_script | profileId, scriptId | Runs a script on one profile; optionally closeBrowserAfter |
get_run_logs | uuid | Reads logs from a direct run |
stop_running_script | uuid | Stops a running script |
The script structure uses settings.elements[], settings.connections[], exactly one start:true, and settings.startElement. Before generating a complex script, the agent should read the afina://docs/rpa-blocks resource and the afina://docs/script-schema schema.
executeModule modules#
| Tool | Required parameters | What it does |
|---|---|---|
list_modules | - | Returns the list of JS modules |
get_module | - | Reads a module by id or hash |
create_module | name | Creates a module and its file directory |
update_module | id | Updates the module row in the DB |
resign_module | id | Recomputes the Ed25519 module signature |
delete_module | - | Soft-deletes a module |
hard_delete_module | - | Deletes the module row and directory |
After editing module files, resign_module is always required. Without a fresh signature, the executor may return modules.error.signature_invalid.
Task groups, tasks, and running across multiple accounts#
| Tool | Required parameters | What it does |
|---|---|---|
list_task_groups | - | Returns task groups |
get_task_group | id | Reads a task group |
get_task_group_tasks | groupId | Reads tasks for a specific group |
create_task_group | - | Creates a group with schedule, timeout, and parallelism |
update_task_group | id | Updates a task group |
start_task_group | id | Activates the group scheduler |
restart_task_group | id | Moves completed tasks back to waiting |
stop_task_group | id | Stops a group |
delete_task_group | id | Soft-deletes a group |
hard_delete_task_group | - | Permanently deletes a group |
add_tasks_to_group | groupId, scriptId, accountIds | Adds tasks to a group |
run_script_on_accounts | scriptId, accountIds | Creates or reuses a group and runs a script as a composite operation |
list_tasks | - | Filters tasks by status, groupId, accountId, scriptId, limit |
get_active_tasks | - | Shows active tasks |
get_task_logs | taskUuid | Reads task logs |
update_task | id | Updates status, executeAt, additionalData, sort, tag, description |
delete_tasks | - | Deletes tasks |
stop_tasks | - | Stops tasks, optionally with closeBrowser |
Key orchestration fields: schedule, timeFrom, timeTo, scheduleTime, startHour, endHour, isRepeatable, repeatCount, timeout, activeSession, waitForOtherTaskCompletion.
Proxies, email, databases, and variables#
| Tool | Required parameters | What it does |
|---|---|---|
check_proxies | - | Checks account proxies by accountIds, groupId, or tagId |
check_all_proxies | - | Checks all saved proxies |
add_proxy | host, port | Adds a proxy after validation |
list_emails | - | Returns IMAP credentials without passwords |
toggle_email | email, isActive | Enables or disables IMAP monitoring |
list_databases | - | Returns database connections |
get_database | id | Reads one connection |
create_database | name | Creates a SQLite/Postgres/MySQL/MSSQL/MongoDB/Redis connection |
update_database | id | Updates a connection |
delete_database | - | Soft-deletes a database |
hard_delete_database | - | Deletes the row and file if filePath exists |
list_global_vars | - | Returns global variables |
create_global_var | name, value | Creates a variable |
update_global_var | id | Updates a variable |
delete_global_var | - | Deletes variables |
list_keys | - | Returns the key catalog |
delete_keys | - | Deletes key names from the catalog |
get_account_vars | - | Reads account variables by account reference |
set_account_var | key, value | Writes a plain or encrypted variable |
delete_account_var | key | Deletes an account variable |
For accounts, the agent should usually call resolve_account first when the user names an account by name, number, or short text reference. resolve_account returns both fields: UUID accountId and numeric id. UUID works for most tools (start_browser, get_account, export_cookies, and others). Exception: run_script_on_accounts, add_tasks_to_group, and check_proxies accept numeric id, not UUID - use the id field from the resolve_account response for these three tools.
Migration from other antidetect browsers#
| Tool | Required parameters | What it does |
|---|---|---|
set_vendor_credentials | vendor, token | Stores a Vision, AdsPower, or Dolphin token |
list_vendor_credentials | - | Shows which vendor credentials are configured |
delete_vendor_credentials | vendor | Deletes vendor credentials |
vision_list_folders | - | Lists Vision folders |
vision_list_profiles | folderId | Lists Vision profiles |
vision_get_profile | folderId, profileId | Full Vision profile |
vision_list_proxies | folderId | Vision proxies |
vision_export_cookies | folderId, profileId | Vision cookies |
vision_import_profiles | folderId, profileIds | Bulk-imports Vision profiles into Afina |
adspower_list_groups | - | AdsPower groups |
adspower_list_profiles | - | AdsPower profiles |
adspower_get_profile | userId | Full AdsPower profile |
adspower_export_cookies | userId | AdsPower cookies |
adspower_import_profiles | userIds | Bulk-imports AdsPower profiles |
dolphin_whoami | - | Dolphin token check |
dolphin_list_profiles | - | Lists Dolphin profiles |
dolphin_get_profile | profileId | Full Dolphin profile |
dolphin_export_cookies | profileId | Dolphin cookies |
dolphin_import_profiles | profileIds | Bulk-imports Dolphin profiles |
Import supports dryRun, withCookies, tagNames, accountGroupNames, and vendor-specific throttling for cookie export.
CDP tools#
| Tool | Required parameters | What it does |
|---|---|---|
cdp_inspect_browser | port | Reads /json/version from any Chromium with CDP |
cdp_export_cookies | port or wsEndpoint | Exports cookies through CDP |
migrate_via_cdp | port or wsEndpoint | Creates an Afina account and moves cookies from a running Chromium |
The CDP approach is needed when the source does not have a public API for cookie export or when you need to quickly move the current authorized session.
Built-in resources#
Afina MCP also exposes resources. These are not tools for actions, but reference documents the agent should read before complex operations.
| URI | When to read |
|---|---|
afina://docs/rpa-blocks | Before generating or editing an RPA script |
afina://docs/script-schema | Before create_script or update_script |
afina://docs/tools-cheatsheet | When it is unclear which MCP tool matches the request |
afina://docs/import-mapping | Before importing from Vision, AdsPower, Dolphin, MoreLogin, Octo, Linken Sphere |
afina://docs/new-vendor-template | When you need to add import from a new vendor |
For scripts and migrations, resources are part of the workflow. A correct agent first reads the reference document and only then calls the write-tool.
Practical scenarios#
Check all proxies before starting activity#
The agent calls check_all_proxies, groups results by result.status, shows slow proxies separately, and does not proceed to a destructive action without confirmation.
Launch a browser and read a page without an RPA script#
Typical flow: resolve_account → start_browser → navigation through eval_in_browser or CDP → get_page_text → take_screenshot → stop_browser.
Run a script on a group of accounts#
The agent should first find the script through list_scripts, resolve accounts through resolve_account or list_accounts, and then use run_script_on_accounts with activeSession: 10, schedule: true, timeFrom: "09:00", timeTo: "15:00", and timeout.
Investigate execution errors#
The agent uses list_task_groups, get_task_group, get_task_group_tasks, and get_task_logs. If the cause is in the script, it reads get_script; if the cause is in proxies, it calls check_proxies for the specific accounts.
Update a JS module after an API change#
Minimum correct flow: list_modules → get_module → edit the module through the available write path → update_module if needed → resign_module. Without resign_module, the module may fail signature validation.
Import profiles from Dolphin#
Correct flow: set_vendor_credentials if the token is not stored yet → dolphin_list_profiles → dolphin_import_profiles with dryRun: true → confirmation → dolphin_import_profiles without dryRun.
Move a session from any Chromium through CDP#
The agent uses cdp_inspect_browser, then migrate_via_cdp or the cdp_export_cookies → create_account → set_cookies chain.
Security and limitations#
- The agent should not see encrypted password values or secret variables; it works with names, metadata, and allowed API responses.
delete_accountis a soft-delete, whilehard_delete_accountpermanently deletes profile rows and files.delete_module,delete_task_group, anddelete_databaseare soft-delete operations;hard_delete_*variants physically delete data.create_one_time_profileautomatically hard-deletes the profile after the browser stops.- For destructive actions, it is better to ask the agent to first show the list of target objects and wait for confirmation.
.mcp.json,claude_desktop_config.json, and.cursor/mcp.jsoncan containAFINA_API_KEY; do not publish these files.
Do not send the agent "delete everything", "clear all profiles", or "hard delete without confirmation" as the first request. First ask for a dry-run list: which accountId, ids, modules, or groups will be affected.
Troubleshooting#
| Problem | Likely cause | What to do |
|---|---|---|
AFINA_API_KEY env is required | The env variable was not provided | Add -e AFINA_API_KEY=... or env in the JSON config |
401 Unauthorized | Invalid API key | Copy the key from Afina again |
afina does not appear in tools | Claude Code has not been restarted | Close the session and open a new one |
npx: command not found | Node.js or npm is not installed | Install Node.js 18+ |
| MCP is connected, but Afina tools fail | Afina is not running or the port is different | Start Afina and check AFINA_URL |
| Browser does not start | Invalid profileId or the account is already in a problematic state | Use resolve_account, then start_browser with UUID |
| Module does not run after editing | resign was not executed | Call resign_module |
| Vendor import does not work | Missing credentials or an incorrect baseUrl | Check list_vendor_credentials and set_vendor_credentials |
Minimal checklist#
After this, the agent can work with Afina as a controlled system: read state, launch browsers, create tasks, analyze logs, edit scripts, and move sessions without manual copying between interfaces.