Give your client an authenticated, audited browser.
The Twin Browser MCP server exposes the execution engine as native tools over stdio. Any MCP client — Cursor, Claude Desktop, Claude Code, Cline, or your own — can compile skills, run goals, replay them with no LLM, and search the shared skill library.
Run the execution engine, then the server
The MCP server runs locally over stdio and forwards to your execution engine. Start the engine first; your MCP client launches the server for you via the config below.
# 1. Start the execution engine (serves the browser pool on :7070).
EXEC_SHARED_SECRET=<your secret> npm run exec
# 2. The MCP server talks to it over stdio. Your MCP client launches it
# for you via the config below — or run it directly to smoke-test:
EXEC_URL=http://localhost:7070 \
EXEC_SHARED_SECRET=<your secret> \
npm run exec:mcpThree ways to wire it up
Point your MCP client at the server with the right environment. Pick the config for your client — the shape is the same.
// .cursor/mcp.json (project) or ~/.cursor/mcp.json (global)
{
"mcpServers": {
"twin-browser": {
"command": "node",
"args": ["src/exec/mcp-server.js"],
"env": {
"EXEC_URL": "http://localhost:7070",
"EXEC_SHARED_SECRET": "<your exec shared secret>",
"WEB_BASE_URL": "https://twin-browser.com",
"TWIN_API_KEY": "ab_live_…"
}
}
}
}// claude_desktop_config.json → mcpServers
{
"mcpServers": {
"twin-browser": {
"command": "node",
"args": ["src/exec/mcp-server.js"],
"env": {
"EXEC_URL": "http://localhost:7070",
"EXEC_SHARED_SECRET": "<your exec shared secret>",
"WEB_BASE_URL": "https://twin-browser.com",
"TWIN_API_KEY": "ab_live_…"
}
}
}
}# Claude Code CLI — register the server in one line. Cline uses the same shape.
claude mcp add twin-browser \
--env EXEC_URL=http://localhost:7070 \
--env EXEC_SHARED_SECRET=<your exec shared secret> \
--env WEB_BASE_URL=https://twin-browser.com \
--env TWIN_API_KEY=ab_live_… \
-- node src/exec/mcp-server.jsEXEC_URL points at your running engine (default http://localhost:7070). EXEC_SHARED_SECRET authenticates the server to the engine. WEB_BASE_URL + TWIN_API_KEY are needed for the web-backed tools — search_library, dispatch, deep_search, etl/etl_query, the monitor tools, and the streamed-run branch of submit_verification — which reach the platform through the web API.Twenty-six tools, one authenticated engine
Lead with dispatch, run_goal, compile_skill and run_skill — the rest cover async jobs, observation, extraction, search, crawl, ETL, monitors, CAPTCHA, recording, and the shared library. Every target-bearing tool is authenticated with your key and acts on the target URL you provide.
run_goalExecute a goal on a target URL you provide — observe, plan, and act until a success condition is met. Optional proxy, video recording, and on-screen annotation. A sign-in run parks by default on a 2FA/approval wall it can’t auto-resolve, returning { status:"paused", sessionId } (resume with submit_verification); pass hitl:false to opt out.
compile_skillDiscover a goal once with the planner, then minimize it into a reusable, deterministic skill.
run_skillBlind-replay a compiled skill with no LLM in the loop — the cheap, deterministic path.
list_skillsList the compiled skills available for replay.
search_librarySemantically search the cross-tenant shared skill library by intent and host (needs WEB_BASE_URL + TWIN_API_KEY).
dispatchThe cheap path: fuzzy-match a goal to an existing compiled skill via the semantic cache — a hit replays deterministically (~5× cheaper), a miss compiles and caches it for next time (needs WEB_BASE_URL + TWIN_API_KEY).
submit_runSubmit a goal as an async background job; returns a job id immediately. Like run_goal, a sign-in job parks by default on a 2FA/approval wall — get_job then reports status:"paused" with a sessionId.
get_jobPoll an async job by id for status, success, steps and result.
cancel_jobCancel a running async job by id (full credit refund).
observe_pageSerialize a page into token-efficient indexed DOM state without taking any action.
screenshotCapture a single screenshot of an authorized URL as PNG or JPEG — full page or one CSS selector. No action, no LLM cost.
extractRead an authorized page and return structured JSON matching the fields or JSON schema you request.
searchWeb search returning ranked results; set fetchContent to also fetch and clean the top results.
deep_searchAsync deep search — search, then scrape the top results (platform-aware) for cleaned content; returns a job id (needs WEB_BASE_URL + TWIN_API_KEY).
map_siteDiscover a site’s URLs fast from sitemap.xml + robots.txt + a shallow link scan. No page content.
submit_crawlCrawl a whole site asynchronously (BFS), bounded by page/depth limits and path globs; returns a job id. Optional per-page structured extraction.
etlRun the ETL pipeline: extract → transform → chunk → embed → load into the queryable content store (needs WEB_BASE_URL + TWIN_API_KEY).
etl_querySemantic search over content ingested with etl; returns the top-k matching chunks (needs WEB_BASE_URL + TWIN_API_KEY).
create_monitorWatch a page on a schedule and push an HMAC-signed webhook when the watched value changes (needs WEB_BASE_URL + TWIN_API_KEY).
list_monitorsList this tenant’s monitors.
delete_monitorDelete a monitor by id.
get_monitor_historyGet a monitor’s recent check history — changed/unchanged/error plus value excerpts.
solve_captchaHand a live/paused session’s CAPTCHA to the solver and continue.
connect_accountGet a one-time link that lets a HUMAN sign into a site by hand, so Twin Browser captures the session and later runs are already logged in. Use it when a run returns code:"credential_missing", or when a site hard-challenges automated logins from datacenter IPs and simply cannot be signed into by an agent. Never ask the user to paste a password — send this link. Re-run the task afterwards and it restores the session (sessionRestored:true).
list_connectionsCheck whether the user finished a connect link you sent them (pending | active | connected | failed | expired) before re-running the task.
control_runDrive a PAUSED run's browser directly — click, type, press a key, scroll, or navigate. Coordinates are 0..1 fractions of the viewport, read off a screenshot. The run continues by itself once the page no longer looks blocked; there is no "done" call. For a login a human must do, prefer connect_account; for a code, submit_verification.
submit_verificationResume a run waiting on a 2FA/approval wall. Two paths: a PARKED run (from run_goal/submit_run) → pass its { sessionId, code } (resumes the engine session directly); a LIVE streamed run → pass its { token, code } (needs WEB_BASE_URL + TWIN_API_KEY). Codes: sms/email, TOTP, or phone approval; or cancel.
record_runRun a goal and capture a video recording of the session.
record_jobSubmit an async job that records its run to video.
Then just ask in natural language
# Once connected, ask your agent in natural language, e.g.:
# "Compile a skill that logs into app.acme.com and exports invoices,
# then replay it." → compile_skill → run_skill (no LLM on replay)
# "Search the library for 'export invoices as CSV' on app.acme.com"
# → search_library
# Every target-bearing call is authenticated with your key and acts on the
# url you pass — scoped to your tenant, metered, and written to the audit log.