dolphin-anty-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@dolphin-anty-mcp Start the profile named jannytest and take a snapshot"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
dolphin-anty-mcp
An MCP server for the Dolphin{anty} anti-detect browser, built from its public OpenAPI document (v1.0.7).
71 tools covering browser profiles, proxies, folders, statuses, fingerprints, cookies, local storage, extensions, homepages, bookmarks and team management — plus page-level automation that drives the Anty browser over the DevTools protocol, and a raw-request escape hatch for anything not modelled explicitly.
Setup
npm install && npm run buildGenerate a JWT at https://dolphin-anty.com/panel/index.html#/api. It is shown once, so copy it before closing the page.
Register the server with your MCP client:
{
"mcpServers": {
"dolphin-anty": {
"command": "node",
"args": ["C:/Users/meow/Documents/Dolphin/dist/index.js"],
"env": { "DOLPHIN_API_TOKEN": "your-jwt-here" }
}
}
}Variable | Default | Purpose |
| — | JWT for the remote APIs. Without it only Local API tools work. |
|
| Local API origin. |
|
| Per-request timeout. |
If port 3001 was busy when Dolphin started, it silently picks the next free port. Check
Settings → Health in the app and set DOLPHIN_LOCAL_API_URL to match.
Related MCP server: Ghost Browser MCP
The two APIs
This matters more than anything else in the setup:
Remote — profiles, proxies, folders, statuses, fingerprints, remote cookies. Works from anywhere with a valid JWT.
Local —
start_profile,stop_profile, cookie robot, local storage. Only answers while the Dolphin{anty} desktop app is running on the same machine, bound to loopback.
Three remote hosts are involved (dolphin-anty-api.com, apiv2.…/api/v2,
darkwing.…/api/v1); each tool is pinned to the right one, so you never pick.
Using a profile by name
People say "spin up jannytest", not "start profile 832201155". start_profile and stop_profile
therefore accept name and resolve it themselves:
{ "name": "jannytest", "automation": true }This exists because the obvious design failed in practice. Every lifecycle endpoint is keyed by
numeric id, so the only tool that took a profile name was create_profile — and a model handed
a name followed the path of least resistance and created a duplicate, silently losing the cookies,
logins and history the user actually wanted.
Three things close that off:
start_profile/stop_profiletakenameand report the id they resolved.create_profilerefuses a name that already exists, naming the existing id and pointing atstart_profile. Override withallowDuplicateName: truewhen a separate profile really is intended.An unresolvable name fails loudly and says not to create a replacement, instead of quietly producing one.
Driving the browser
create_profile → coherent fingerprint attached automatically
start_profile → automation endpoint cached; browser_* tools attach on their own
browser_snapshot → see the page as an accessibility tree
browser_click/type → act on it
stop_profile → syncs the data directory back to the cloudSkipping stop_profile leaves the session's cookies and storage unsynced.
Targeting. browser_snapshot prints lines like button "Log in" — the role and quoted name
are exactly what target takes:
{ "profileId": 123, "target": { "role": "button", "name": "Log in" } }Fall back to text, label, placeholder, testId or raw css; add nth when several match.
There are no opaque element refs to keep in sync, because ariaSnapshot({ ref: true }) does not
actually emit them in playwright-core 1.62 — role+name is what the snapshot gives you, so it is
what the tools consume.
Snapshot first, act second. browser_screenshot exists but costs far more context; reach for it
only when the visual rendering itself matters.
Tabs
browser_tabs lists, opens, switches and closes tabs. Every other browser tool also takes a
tabIndex.
{ "profileId": 123, "action": "list" } → [0] Inbox — https://…
{ "profileId": 123, "action": "select", "index": 1 } → switch for good
{ "profileId": 123, "action": "new", "url": "https://…" }
{ "profileId": 123, "action": "close", "index": 1 }The two are deliberately different. action: "select" changes the active tab for every later
call; tabIndex acts on one tab for a single call and leaves the active tab alone. That split
matters — a read-only browser_snapshot { tabIndex: 2 } silently redirecting all subsequent
clicks to tab 2 is the kind of thing a model never recovers from.
Popups are reported on the action that caused them. A target="_blank" link leaves the
current page looking unchanged, so a click that spawns a tab appends:
🔗 1 new tab(s) opened — the snapshot above is still the original tab:
[1] https://example.com/b
Use browser_tabs { action: "select", index: 1 } to switch to it, or pass tabIndex to peek.The new tab is not auto-selected — the model is told and decides. Detection uses the context's
page event rather than comparing tab counts, because the popup registers a moment after the
click resolves and a count check races it.
CAPTCHAs and human handoff
The server detects human-verification challenges and stops. It does not solve or bypass them — automated attempts fail and get the profile flagged.
Every navigation, click and snapshot is checked for reCAPTCHA, hCaptcha, Cloudflare Turnstile and its interstitial, Arkose/FunCaptcha, DataDome, PerimeterX, GeeTest, and generic "verify you are human" text. When one is found the tool result carries an explicit instruction:
⚠️ HUMAN VERIFICATION DETECTED: reCAPTCHA (widget present and visible on the page).
Do NOT try to solve, click or type your way through this … Call `browser_await_human` …browser_await_human brings the window to the front, shows the operator your reason, and blocks
until the challenge clears — then returns a fresh snapshot so the run continues. It also covers
login walls, 2FA/OTP prompts, SMS codes and payment steps.
{ "profileId": 123, "reason": "Solve the reCAPTCHA on the login page", "timeoutSeconds": 300 }Two things make this reliable with weaker models. The instruction is embedded in the tool output, where a model that has just walked into a captcha will actually read it, rather than only in a description it saw once. And on timeout the tool says "ask the operator, do not loop" instead of returning something retryable.
Where the host supports MCP elicitation, the operator gets a real prompt and confirms when
done. Where it does not — most harnesses today — the tool falls back to polling the page, so the
behavior is the same either way. until accepts challengeGone (default), urlChanged,
textPresent, textGone, or manual.
Handoff requires a headed profile; the tool refuses immediately on a headless one rather than blocking on a window nobody can see.
Connecting your own client instead
const url = `ws://127.0.0.1:${port}${wsEndpoint}`;
await chromium.connectOverCDP(url); // Playwright
await puppeteer.connect({ browserWSEndpoint: url }); // PuppeteerBoth fields are needed. The OpenAPI document describes wsEndpoint as a full ws:// URL, but a
live build returns a bare path — see below.
The MCP resource dolphin://guide/automation carries the full workflow, including hand-tuning a
fingerprint instead of letting create_profile do it.
Fingerprints
Dolphin does not generate fingerprints server-side, and an incoherent one defeats the point of
an anti-detect browser. create_profile therefore pulls a real fingerprint from Dolphin's dataset
and attaches it by default. Pass your own fingerprint object (from get_fingerprint) to
override, or autoFingerprint: false to send none.
One asymmetry worth knowing: create_profiles_bulk ignores a nested fingerprint object.
Bulk creation needs the fields flattened to the top level (useragent, uaFullVersion,
screenWidth, cpu, webglInfo, …). The tool description repeats this.
Tools
Group | Tools |
Profiles |
|
Lifecycle |
|
Proxies |
|
Folders |
|
Statuses |
|
Fingerprints |
|
Cookies |
|
Local storage |
|
Extensions |
|
Homepages |
|
Bookmarks |
|
Team |
|
Browser |
|
Escape hatch |
|
Deletes and transfers carry destructiveHint annotations, so clients that gate on those will
prompt before running them.
Some tools collapse several endpoints where the API split them arbitrarily: delete_profiles
routes single-id deletes through the per-profile endpoint (the only one that accepts a profile
password), move_profiles_to_folder attaches or detaches depending on whether you pass a
folderId, and assign_status either references an existing status or creates one inline.
Error handling
HTTP status codes get translated into something actionable rather than surfaced as bare numbers:
Code | Meaning |
401 | JWT missing or expired |
402 | Paid-plan feature — automation, cookie robot, remote cookies |
429 | 500 req/min rate limit, or too many concurrent launches |
499 | Free plan: three profiles already running |
Rate-limit headers are read on every response; when fewer than 25 requests remain in the current
minute, the tool result says so. Connection failures against the Local API explain the desktop-app
and port requirements instead of returning a bare ECONNREFUSED.
Responses are capped at 60k characters — a page of 100 profiles carries a full fingerprint each, which would otherwise flood the context window.
Not covered
POST /extensions/upload-zipped— multipart file upload.dolphin_requestsends JSON only, so this endpoint is genuinely unreachable through this server. Use the app or a direct HTTP call.getFolder,getBrowserProfileStatus, the single-profileshareAccessToBrowserProfile, and the multi-profile local-storage export are reachable viadolphin_request— they were left out because a dedicated tool would duplicate one that already exists.
Real-world run
node examples/bot-detection-check.mjsDrives a real Anty profile through bot.sannysoft.com and then a live DuckDuckGo search, using only MCP tools. Result: 58 detection tests, 0 failures or warnings.
✅ WebDriver (New) missing (passed)
✅ WebDriver Advanced passed
✅ Chrome (New) present (passed)
✅ Permissions (New) prompt
✅ Plugins Length (Old) 5
✅ HEADCHR_UA / _CHROME_OBJ / _PERMISSIONS / _PLUGINS ok
✅ WebGL Renderer ANGLE (Intel, Intel(R) Iris(R) Xe Graphics …)The interactive half found the search box by role from a snapshot, typed, submitted, and read the
results back — which included API - Dolphin {Anty}. So CDP automation through this server does
not break the profile's anti-detect properties.
Findings from a live build
Measured against Dolphin{anty} running Anty 150 on Windows 11, using temporary profiles.
wsEndpoint is a path, not a URL. The OpenAPI document says "Full ws:// URL" and gives
ws://127.0.0.1:38927/devtools/browser/abc123 as its example. The actual response is
{"port": 59618, "wsEndpoint": "/devtools/browser/8e0a4ca0-…"} — a bare path, matching Dolphin's
own automation blog post rather than its spec. This server accepts either shape.
A nested fingerprint object produces a broken profile. The docs say you can pass the whole
fingerprint to POST /browser_profiles and "the backend flattens its derived fields for you". It
does not. The profile is created, but GET /browser_profiles/{id} and the Local API's start
endpoint both then return HTTP 500. create_profile flattens it here instead, into the
{mode, value} shape a profile actually stores:
useragent {"mode":"manual","value":"Mozilla/5.0 …"}
cpu {"mode":"manual","value":8}
webglInfo {"mode":"manual","vendor":"Google Inc. (NVIDIA)","renderer":"ANGLE (NVIDIA, …)"}A profile without spoofing-mode objects cannot launch. Create accepts a body with no webrtc,
canvas, webgl, clientRect, timezone, locale, ports or geolocation and stores them as
null. The profile reads back fine and then fails to start with HTTP 500. create_profile now
sends the same defaults a UI-built profile carries (PROFILE_MODE_DEFAULTS in
src/fingerprint.ts).
browser_version is required on /fingerprints/fingerprint, and there is no fallback. The
spec marks it optional and says omitting it (or passing a version above stable) falls back to an
internal default. Neither is true: omitting it returns HTTP 422 validation.required, and a
too-high value returns HTTP 200 with an empty object. create_profile's default path was broken by
this. It now discovers the dataset's current maximum by binary search and caches it
(src/fingerprint-version.ts) rather than hard-coding a version that
would rot — requesting a year-old Chrome is itself a fingerprinting signal. At the time of writing
the dataset covers up to Chrome 150.
fonts silently does not persist. Sending a 214-entry fonts array stores []. Pairing that
with fontsMode: "manual" yields a browser reporting zero fonts — a louder signal than not
spoofing at all. Fonts are therefore left at Dolphin's auto, which is also what UI-built profiles
use.
Headless leaks HeadlessChrome — but only on temporary profiles.
profile | headed |
|
temporary |
|
|
saved (via |
|
|
Temporary profiles use default fingerprint preferences and carry no user-agent of their own, so
the headless token shows through. A saved profile's manual user-agent overrides it — verified
byte-identical in both modes. start_temporary_profile warns when headless is set;
start_profile does not, because it does not need to.
navigator.webdriver is false and no cdc_/$cdc_ CDP artifacts are injected in either mode.
page.setContent fails on Anty's default page with a TrustedHTML error — its internal pages
enforce Trusted Types. Navigate to a real URL instead. No tool here uses setContent.
Detaching does not kill the browser. browser.close() on a CDP-attached connection releases
the client while Dolphin keeps the process alive, so browser_disconnect is safe and
stop_profile remains the only thing that ends a session and syncs its data.
Tests
npm run build
npm test # everything below
npm run smoke # mock Local API, no app required
npm run e2e # real Dolphin{anty}; skips itself if the app is not runningsmoke runs the built server over stdio against a mock and asserts on the tool surface, routing,
query serialization, error translation and input validation.
e2e starts a real temporary profile through the Local API and drives the actual Anty browser:
navigate, snapshot, type, select, click, evaluate (page and element scope), scroll, tabs,
screenshot, ambiguous-target error handling, and a real request to example.com. The fixture page
is served locally so assertions are deterministic, but the browser under test is genuinely the one
Dolphin launched.
test/challenge.e2e.test.js covers the handoff path and tab handling: each vendor's widget markup is detected,
an ordinary page does not false-positive, browser_await_human returns as soon as a challenge
clears (~6s, not the full timeout), it times out without looping, and a live Google reCAPTCHA
demo page is recognised. It never attempts to solve one.
test/profile-lookup.e2e.test.js pins the name-resolution behavior against a live account:
duplicate names are refused, the refusal is overridable, start_profile resolves a name to the
existing id, and an unknown name fails without creating anything.
33 tests total, all passing. Run them serially — npm test sets --test-concurrency=1, because
the two e2e files each launch a browser and collide over profile data directories in parallel.
Both API halves are now verified against a live account:
node examples/remote-check.mjs # read-only sweep of the cloud endpoints
node examples/fingerprint-verify.mjs # create → launch → assert fingerprint → clean upremote-check confirms list_profiles, list_proxies, list_folders, list_statuses,
get_fingerprint, get_useragent, list_fonts and list_team_users against real data.
fingerprint-verify creates a profile from a dataset fingerprint, launches it headless and headed,
and asserts the spoof actually applied — user-agent, core count, memory, screen resolution and
WebGL renderer all matched the requested values exactly. It deletes the profile it created.
Still unverified: cookie import/export, local storage, homepages, bookmarks, extensions, folder
and team mutations. dolphin_request is the workaround if one of those has a field mismatch.
Local API session
Starting a saved profile needs the desktop app to hold a valid session. If start_profile
returns HTTP 500 while start_temporary_profile works, run local_api_login — it stores your JWT
in the app. Note that GET /v1.0/browser_profiles returning invalid session token is not a
signal of this; that endpoint uses the app's own internal session and 401s regardless.
Available Tools
71 toolsadd_extensionAdd an extension from the Chrome Web StoreA
Add a public Chrome Web Store extension so it can be attached to profiles. The URL must start with https://chrome.google.com/webstore/detail/ or https://chromewebstore.google.com/detail/. Private or unpublished extensions are rejected. To add a packed .zip instead, use dolphin_request against /extensions/upload-zipped (multipart).
Inputs: url (required), mainWebsite, sharedToEntireTeam.
assign_statusAssign a status to profilesA
Set the status of several profiles at once. Pass statusId for an existing status, or name + color to create one on the fly and apply it.
Inputs: ids (required), name, color, statusId.
browser_await_humanPause for a humanA
Hand control to a person and wait. Use this the moment you hit anything a human must do: a CAPTCHA, a Cloudflare check, a login wall, a 2FA/OTP code, an SMS confirmation, or a payment step.
Do NOT try to solve a CAPTCHA yourself — clicking or typing at one fails and gets the profile flagged. Call this instead. It brings the browser window to the front, tells the operator what to do, and blocks until the page clears the challenge (or until timeoutSeconds). It then returns a fresh snapshot so you can carry on.
The profile must be running headed — a person cannot act on a headless window.
Inputs: reason (required), profileId (required), text, until, +3 more.
browser_clickClick or hover an elementA
Click, double-click, right-click or hover an element. Waits for it to be actionable first. Returns a snapshot of the page afterwards.
Inputs: target (required), profileId (required), action, timeout, +2 more.
browser_connectAttach to a running profileA
Attach the automation client to a profile that is already running with automation enabled. Usually unnecessary — start_profile records the endpoint and the browser_* tools attach on demand. Use this when the profile was started outside this server, passing the port and wsEndpoint from that start call. Set start: true to have this tool start the profile itself.
Inputs: profileId (required), port, start, headless, +1 more.
browser_disconnectDetach from a profileAIdempotent
Release the automation connection. The browser keeps running — use stop_profile to actually close it and sync its data directory back to the cloud.
Inputs: profileId (required).
browser_evaluateRun JavaScript in the pageA
Evaluate an expression in page context and return the result as JSON. The escape hatch for reading values the accessibility tree does not expose. Prefer browser_snapshot for reading structure and browser_click for interacting — synthetic events dispatched from here behave differently from real input and some sites notice.
Inputs: profileId (required), expression (required), target, tabIndex.
browser_press_keyPress a keyA
Send a keyboard key to the page or to a focused element. Accepts Playwright key names: Enter, Tab, Escape, ArrowDown, PageDown, Backspace, or chords like Control+A.
Inputs: key (required), profileId (required), repeat, target, +1 more.
browser_screenshotScreenshot the pageARead-only
Capture the page as an image. Costs far more context than browser_snapshot, so reach for it only when the visual rendering matters — layout problems, canvas, captcha-looking elements, or verifying something a text tree cannot express.
Inputs: profileId (required), format, target, quality, +2 more.
browser_scrollScrollA
Scroll the page, or bring a specific element into view. Useful for lazy-loaded content that is not in the DOM until it is scrolled to.
Inputs: profileId (required), amount, target, tabIndex, +1 more.
browser_select_optionSelect a dropdown optionA
Choose one or more options in a . Match by visible label or by value.
Inputs: target (required), profileId (required), labels, values, +2 more.
browser_snapshotSnapshot the pageARead-only
Read the page as an accessibility tree — roles, accessible names and structure. This is the primary way to see a page: it is compact, text-only, and its role "name" pairs are exactly what browser_click and browser_type take as targets. Prefer it over browser_screenshot unless you specifically need to see the visual rendering.
Inputs: profileId (required), target, tabIndex.
browser_tabsManage tabsA
List, open, switch or close tabs. Every other browser tool acts on the active tab unless given an explicit tabIndex.
Inputs: profileId (required), url, index, action.
browser_typeType into a fieldA
Enter text into an input, textarea or contenteditable. Replaces the existing value by default. Set pressEnter to submit, or mode: 'press' to send real per-key events when a page listens for keydown (autocompletes and search-as-you-type usually do).
Inputs: value (required), target (required), profileId (required), mode, +5 more.
browser_wait_forWait for somethingARead-only
Wait for text to appear or disappear, for an element, for a load state, or for a fixed delay. Use this instead of retrying a failed click when a page is still settling.
Inputs: profileId (required), text, state, target, +4 more.
create_bookmarkCreate a bookmarkA
Create a bookmark that can be pushed into browser profiles.
Inputs: url (required), name (required), mainWebsite, sharedToEntireTeam.
create_folderCreate a folderA
Create a folder for grouping profiles.
Inputs: name (required), emoji, isPinned.
create_homepagesCreate homepagesB
Create up to 10 startup pages in one call.
Inputs: data (required), mainWebsite, sharedToEntireTeam.
create_profileCreate a browser profileA
Create a NEW browser profile. If the user named a profile and asked you to open, run or 'spin up' it, that is start_profile with name — not this tool. Creating a lookalike loses every cookie, login and bit of history the real one holds. This tool refuses a name that already exists unless allowDuplicateName is set.
By default this pulls a real, internally coherent fingerprint from the Dolphin dataset and applies it — which is what you want, since Dolphin does NOT generate fingerprints server-side and an incoherent one defeats the point of an anti-detect browser. The fingerprint is flattened into the profile's own field shape (useragent/cpu/memory/webglInfo as {mode,value} objects); handing the API a nested fingerprint object as its docs suggest produces a profile that cannot be read or started. Pass fingerprint from get_fingerprint to choose one yourself, or set autoFingerprint: false to create a bare profile.
Inputs: name (required), platform (required), args, tags, +10 more.
create_profiles_bulkBulk create browser profilesA
Create many profiles in one call. Important: unlike create_profile, the backend IGNORES a nested fingerprint object here — fingerprint data must be supplied as flattened top-level keys (useragent, uaFullVersion, screenWidth, screenHeight, cpu, memory, connectionRtt, webglInfo, …). Use common for values shared by every item; per-item values win on conflict.
Inputs: items (required), common.
create_proxyCreate a proxyA
Save a proxy in the workspace so it can be attached to profiles. The connection itself is made by the Dolphin app on the machine running the profile, not by this server.
Inputs: host (required), port (required), type (required), name, +3 more.
create_statusCreate a profile statusA
Create a coloured status label for grouping and filtering profiles, optionally applying it to a profile straight away.
Inputs: name (required), color (required), profile, password.
create_team_userCreate a team memberB
Add a member to the team. Only admins can do this.
Inputs: role (required), password (required), username (required), bpLimit, +4 more.
delete_bookmarksDelete bookmarksBDestructiveIdempotent
Delete bookmarks from the workspace.
Inputs: ids (required).
delete_extensionsDelete extensionsADestructiveIdempotent
Remove extensions from the workspace. Profiles using them lose them on next launch.
Inputs: ids (required).
delete_folderDelete a folderADestructiveIdempotent
Delete a folder. Profiles inside it are detached, not deleted.
Inputs: id (required).
delete_homepagesDelete homepagesBDestructiveIdempotent
Delete startup page entries.
Inputs: ids (required).
delete_profilesDelete browser profilesADestructiveIdempotent
Delete one or more profiles. On paid plans they move to the Basket by default; forceDelete: true removes them permanently and is mandatory on Free plans. browserProfilePassword is only accepted when deleting exactly one password-protected profile.
Inputs: ids (required), forceDelete, browserProfilePassword.
delete_proxyDelete a proxyADestructiveIdempotent
Remove a saved proxy. Profiles referencing it are left without one.
Inputs: id (required).
delete_statusesDelete profile statusesADestructiveIdempotent
Delete status labels. Profiles carrying them are left with no status.
Inputs: ids (required).
delete_team_userDelete a team memberADestructiveIdempotent
Remove a member from the team. Admins only.
Inputs: userId (required).
dolphin_requestCall any Dolphin{anty} API endpointA
Raw, unvalidated call to the Dolphin{anty} API. Use this only when no dedicated tool fits — the typed tools carry validation and API-specific guidance this one does not.
Pick target by which host owns the endpoint:
v1→ https://dolphin-anty-api.com (profiles, proxies, folders, statuses, fingerprints, extensions)v2→ https://apiv2.dolphin-anty-api.com/api/v2 (homepages, bookmarks, team reads)sync→ https://darkwing.dolphin-anty-api.com/api/v1 (remote cookie import/export)local→ the desktop app's Local API (profile start/stop, cookie robot, local storage)
Array query values are joined with commas, matching the API's explode: false style.
Inputs: path (required), method (required), target (required), body, +1 more.
export_cookiesExport cookies from a profileARead-only
Read a profile's cookies via the remote sync API — no desktop app required. The profile must have cloud sync enabled, and this is a paid-plan feature. Returns an empty array if the profile has never synced.
Inputs: browserProfileId (required), browserProfilePassword.
export_cookies_localExport cookies via the Local APIA
Export cookies for one or more profiles through the running desktop app. As a side effect this writes a dolphin-anty-cookies--.txt file per profile into the machine's Downloads folder. Prefer export_cookies unless you need that file or the profile is not cloud-synced.
Inputs: browserProfiles (required), plan.
export_local_storageExport local storageARead-only
Export a profile's local storage through the desktop app, grouped by origin. Keys and values are Base64-encoded and are normally treated as an opaque blob.
Inputs: browserProfileId (required), plan, cloudSyncDisabled, browserProfilePassword.
get_fingerprintGet a browser fingerprintARead-only
Sample a real-world fingerprint from the Dolphin dataset. Pass the returned object verbatim as create_profile's fingerprint — the values are internally consistent and editing them piecemeal is what trips anti-fraud systems. Note: when nothing matches the filters the API returns HTTP 200 with an empty object.
Inputs: platform (required), screen, browser_version.
get_folder_profile_idsList profile ids in a folderARead-only
Return the profile ids inside a folder plus whether any of them is password-protected.
Inputs: id (required).
get_profileGet a browser profileARead-only
Fetch one browser profile by id, including its full fingerprint.
Inputs: id (required).
get_useragentGet a user-agent stringARead-only
Sample a real user-agent matching a platform and major Chrome version. Keep it consistent with the rest of the profile's fingerprint.
Inputs: platform (required), browser_version (required), oldUseragent.
import_cookiesImport cookies into a profileA
Write cookies into a profile via the remote sync API — no desktop app required. Existing cookies with the same domain/path/name are replaced. The profile must have cloud sync enabled, and this is a paid-plan feature.
Inputs: cookies (required), browserProfileId (required), browserProfilePassword.
import_cookies_localImport cookies via the Local APIA
Write cookies into a profile's on-disk data directory through the running desktop app. Prefer import_cookies unless the profile has cloud sync disabled.
Inputs: cookies (required), profileId (required), cloudSyncDisabled, browserProfilePassword.
import_local_storageImport local storageA
Write a local storage dump (as produced by export_local_storage) into a profile through the desktop app.
Inputs: profileId (required), localStorage (required), plan.
list_bookmarksList bookmarksCRead-only
List the bookmarks available to assign to profiles.
Inputs: page, limit, query, mainWebsites.
list_extensionsList extensionsARead-only
List the browser extensions available to attach to profiles.
Inputs: page, limit, query.
list_foldersList foldersARead-only
List the folders used to group browser profiles in the workspace.
Inputs: no named parameters.
list_fontsList fonts for a platformARead-only
List font families that genuinely exist on the given OS. To use them in a profile, extract just the font property from each record into a string array, set that as fonts, and set fontsMode to manual.
Inputs: platform (required).
list_homepagesList homepagesARead-only
List the startup pages available to assign to profiles.
Inputs: page, limit, query, mainWebsites.
list_profilesList browser profilesARead-only
List browser profiles with pagination, full-text search and filters. Each item carries a full fingerprint, so keep limit small (default 10) unless you really need the raw data.
Inputs: page, tags, limit, order, +8 more.
list_profiles_cursorList browser profiles (cursor pagination)ARead-only
Cursor-paginated profile listing. Prefer this over list_profiles when walking a large workspace: pass the cursor from the previous response's next_page_url and keep every other parameter identical.
Inputs: tags, limit, order, query, +5 more.
list_proxiesList proxiesARead-only
List proxies saved in the workspace, with optional search and pagination.
Inputs: page, limit, query.
list_statusesList profile statusesARead-only
List the custom status labels available for tagging profiles.
Inputs: no named parameters.
list_team_usersList team membersARead-only
List members of the current team account, with their roles and profile limits.
Inputs: page, limit, query.
list_webglList WebGL vendor/renderer pairsARead-only
List GPU adapter combinations available for a platform. When swapping these into a fingerprint, always copy the vendor/renderer pair together (and the webgl2Maximum block when withMaximum is set) so WebGL1 and WebGL2 data stay in sync.
Inputs: platform (required), withMaximum, browser_version.
local_api_loginAuthenticate the Local APIA
Store the remote JWT inside the running Dolphin{anty} desktop app and validate it. Defaults to the token this server is configured with.
Inputs: token.
move_profiles_to_folderAttach or detach profiles from foldersA
Attach profiles to a folder, or detach them from whatever folder they are in. Omit folderId to detach.
Inputs: profileIds (required), folderId, password.
reorder_foldersSet folder display orderA
Reorder folders in the UI. Higher order values sort higher in the list.
Inputs: folders (required).
run_cookie_robotRun the cookie robotA
Warm up a profile by visiting a list of URLs in a short-lived browser and saving every resulting cookie to that profile. Runs sequentially through the URLs. Paid plans only, and requires the desktop app. Progress is reported over Socket.IO, which this server does not subscribe to — the call returns as soon as the robot has started.
Inputs: data (required), browserProfileId (required), headless, imageless, +1 more.
start_profileStart a browser profileA
Launch an EXISTING browser profile. This is the tool for 'open/run/spin up ' — identify it by name if that is what the user gave you, or by browserProfileId. Never route a named profile to create_profile: a new profile has none of the original's cookies, logins or history, so it is not the profile the user meant.
Pass automation: true to drive the page with the browser_* tools afterwards, then stop_profile to sync the data directory back to the cloud. Requires the Dolphin{anty} desktop app to be running.
Inputs: dpr, name, noTabs, headless, +7 more.
start_temporary_profileStart a temporary browser profileA
Launch a throwaway profile with a fresh data directory and default fingerprint preferences. Returns the generated profileId. Useful for one-off sessions you do not want persisted in the workspace.
Inputs: dpr, headless, automation, screenWidth, +1 more.
stop_cookie_robotStop the cookie robotAIdempotent
Stop a running cookie robot. No-op if it is not running.
Inputs: browserProfileId (required).
stop_profileStop a browser profileAIdempotent
Gracefully stop a running profile and sync its data directory back to the cloud. Safe to call when the browser has already exited — it still reports success.
Inputs: name, afterReAuth, retryToStop, browserProfileId.
transfer_profilesTransfer profiles to another userADestructive
Move profiles to another Dolphin{anty} account by email. You must own the profiles or hold the share permission. Note the backend quirk: if the recipient email does not exist the call still reports success but nothing is transferred.
Inputs: ids (required), username (required), withProxy.
update_bookmarkUpdate a bookmarkA
Change a bookmark. Only the fields you pass are modified.
Inputs: id (required), url, name, mainWebsite, +1 more.
update_folderUpdate a folderA
Rename a folder, change its emoji, or pin/unpin it.
Inputs: id (required), name, emoji, isPinned.
update_homepageUpdate a homepageA
Change a startup page entry. Only the fields you pass are modified.
Inputs: id (required), data, mainWebsite, sharedToEntireTeam.
update_profileUpdate a browser profileA
Patch an existing profile. Only the fields you pass change; everything else is left alone. Use extra for any field this tool does not model explicitly.
Inputs: id (required), args, name, tags, +9 more.
update_proxyUpdate a proxyA
Change a saved proxy. Profiles already using it pick up the new settings on next launch.
Inputs: id (required), host, name, port, +4 more.
update_statusUpdate a profile statusA
Rename a status or change its badge colour.
Inputs: id (required), name, color.
update_team_userUpdate a team memberA
Change a team member's role, credentials, supervisors or profile limits. Admins only.
Inputs: userId (required), role, bpLimit, password, +5 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 71 tools
Each tool targets a distinct resource/action, with detailed descriptions that clarify edge cases (e.g., list_profiles vs list_profiles_cursor, export_cookies vs export_cookies_local). The main risk is the sheer number of similarly named tools, but the descriptions resolve most ambiguity.
The dominant pattern is verb_noun (list_, create_, update_, delete_, get_, start_, stop_, browser_), which is predictable. Minor deviations exist: plural forms (delete_profiles, create_profiles_bulk), the suffix in list_profiles_cursor, and the catch-all dolphin_request, but these do not obscure the convention.
At 71 tools, this is far above the 25+ threshold for 'too many' and will be heavy for an agent to navigate. While the tools cover a wide range of the Dolphin{anty} product's features, the sheer volume makes the server feel like a kitchen sink rather than a focused toolset; splitting into modular servers would improve coherence.
The surface is remarkably complete: CRUD for profiles, proxies, folders, statuses, bookmarks, homepages, extensions, and team members, plus fingerprint generation, cookie sync, and browser automation. Minor gaps like a dedicated get_proxy are covered by list endpoints, so there are no functional dead ends.
Maintenance
Related MCP Connectors
Web scraping MCP server — scrape, extract structured data, screenshot any site with anti-bot bypass.
Official Browserless MCP server: browser automation, scraping, screenshots and PDFs for AI agents.
Hosted MCP server for DataLikers — Instagram & TikTok data API. 51 tools: Instagram user search by demographics (gender/age/race/country/city), profiles, bulk lookup, engagement, posts & reels, comments, hashtags, locations, stories, highlights, music, business accounts, top users; TikTok users, videos, comments, hashtags, playlists and top charts. Streamable HTTP, Bearer API key. Free tier: 100 requests on signup at https://datalikers.com/p/1by27bwg
The MCP server for Azure DevOps, bringing the power of Azure DevOps directly to your agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server that provides tools for interacting with Chrome through its DevTools Protocol, enabling remote control of Chrome tabs to execute JavaScript, capture screenshots, monitor network traffic, and more.58 npm52MIT
- -licenseNot gradedqualityNot gradedmaintenanceUndetectable browser automation server for MCP-compatible AI agents, offering 225 tools across 32 sections to navigate, extract, clone pages, and bypass antibot systems like Cloudflare.1-
- FlicenseNot gradedqualityNot gradedmaintenanceSelf-hosted MCP server for browser automation with stealth patches, offering 50 tools for navigation, scraping, and session configuration. Runs via Docker and supports remote control from any MCP client.-

dsh-antibrowofficial
AlicenseNot gradedqualityCmaintenanceAn MCP server that provides an antidetect browser with persistent profiles, proxy support, and page control tools (16 tools) for agents, enabling identity-stable browsing sessions across runs.12MIT