Ghosthand
This server provides a local, free, human-like browser automation engine designed for AI agents, testing, and workflows. It drives a real Chrome browser (including your actual profile with cookies and logins) with realistic cursor movement (Fitts's law timing, overshoot, jitter) to evade bot detection.
Page Reading & Discovery
read_page— Scan the page for interactive elements, returning stable[ref]handles, roles, names, and on-screen rectanglesfind— Locate elements by visible text or accessible name (shadow-DOM aware)get_url— Retrieve the active tab's current URLstatus— Check server health and browser connection
Navigation
navigate— Load any URL in the active browser tab
Mouse Interaction
click— Click an element by[ref]orx/ycoordinates; supports left/right/middle button and double-clickclick_text— Find an element by text and click it in one stepmove_to— Move the cursor without clickinghover— Fire hover events (for dropdowns, tooltips, menus)drag— Human-like drag between elements or coordinates (sliders, reordering, canvas)
Keyboard Interaction
type— Type text with human-like timing; optionally focuses a ref firstpress_key— Press a single key (Enter, Escape, Tab, arrows, etc.)
Scrolling
scroll— Scroll the page with eased, human-like steps
Waiting & Synchronization
wait_for— Wait until an element or text appears on the page
Visual Capture
screenshot— Capture the visible tab scaled so 1 image pixel = 1 click coordinate, enabling a vision loop (see → decide → click)
Stealth / Anti-Detection
Most tools support a
stealth: trueflag to deliver trusted events via Chrome Debugger Protocol (CDP), and an OS cursor driver is available on macOS for advanced bot evasion.
Integration
Usable as an MCP server for AI agents (Claude, Cursor, Grok) or via a JavaScript/TypeScript SDK with a Playwright-shaped locator API.
Click on "Install 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., "@Ghosthandfind the 'Add to Cart' button and click it"
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.
AgentCursor
Local, free, human-like browser automation over MCP — for agents, testing, and workflows.
AgentCursor gives you (and any coding agent or automation script) a real browser driven with visible, convincingly human cursor movement and timing.
Use it as:
A powerful MCP tool for Claude, Cursor, Grok, custom agents, etc.
A realistic E2E / acceptance testing tool that works on actual production sites (human paths + timing are more resilient than robotic Playwright clicks).
A workflow automation engine for complex multi-step processes (logins, form flows, data entry, admin tasks) with natural hover, move, type, and scroll behavior.
A debugging / demo automation tool (the cursor is visible so you can watch exactly what the automation did).
All local. All free. MIT licensed. No cloud, no paywalled stealth.
The major browser automation MCPs often make realistic movement a cloud-only feature. AgentCursor brings the realistic cursor to your local machine for agents and traditional testing/automation use cases.
Status: phase 1 (Chrome extension) and phase 2 (macOS OS-cursor for genuinely trusted events) are both implemented. See
docs/DESIGN.md.
Changelog (key updates)
0.3.0: Programmatic SDK —
import { AgentCursor } from "agentcursor"with a Playwright-shaped locator API (getByRole/getByText/getByLabel/getByPlaceholder/getByTestId/css + chaining +filter/nth+click/type/fill/hover/dragTo/press/scrollIntoView+boundingBox/isVisible/count/waitFor), every action driven by the human cursor.connect()andos()lifecycles. Library entry split from the MCP bin so importing the package no longer boots a server; built withtsup(ships.d.ts). Locator resolution uses@testing-library/domin the content script.0.2.9: Active-tab resolution no longer requires Chrome to be the OS-focused window — it falls back to the active tab in any window, then any open http(s) tab. Fixes
No active tab foundwhen an agent drives the browser while you're in your editor/terminal (the normal case).0.2.8: Interaction:
press_key— press Enter / Escape / Tab / arrows / Home / End / etc. on the focused element, content or stealth (trusted CDP key event). Rounds out the Comet-style action set: Navigation, Identification, Interaction.0.2.7: Identification tools —
find(locate elements by visible text / accessible name, shadow-DOM aware) andclick_text(find the best text match, then human-move + click, content or stealth, with a re-read retry). Target by what the element says, not by ref or pixel coords.0.2.6: Stealth typing inserts the whole string in one
Input.insertTextcall. Per-character insertion landed at a reset caret on controlled editors (X's Draft.js) and typed text backward.0.2.5: Content-script
dragreports the held button (buttonsmask) during the move, matching the stealth and OS drivers, so JS drag handlers see a real drag. Added a Known Limitations section.0.2.4:
read_pageresolves multi-IDaria-labelledbynames (it was passing the whole space-separated list togetElementByIdas one ID, so those labels came back empty); now shadow-DOM-tree-scope aware.0.2.3:
dragnow performs a real drag (press at the start, move with the button held, release at the end) in the stealth (chrome.debugger) and OS-cursor drivers — previously a move-then-click.pnpm smokeasserts thescreenshotimage content.0.2.2:
dragtool.screenshotnow returns a viewport-scaled image (1 image pixel = 1 click coordinate) for a vision loop — see the page, thenclick/move_tobyx/y. Stealth (chrome.debugger) moves also animate the visible overlay, so the cursor stays on screen. Ships as a Claude Code plugin. Internal snapshot refresh resolves refs past the 60th element.pnpm buildno longer mutates version files (usepnpm reloadfor the extension dev loop).0.2.0: Added
screenshot,hover,statusMCP tools. Deep shadow DOM traversal inread_page/ snapshot (critical for X.com, Reddit, modern SPAs). Library re-exports for programmatic use. Repositioned as general local automation/testing/workflow tool over MCP. Version bumps and packaging polish.0.1.0: Initial MCP server, human path engine, extension bridge, OS cursor driver, basic tools (read_page, click, type, etc.).
Related MCP server: Browserbeam MCP Server
How it works
Three layers, with one shared wire contract (src/protocol):
coding agent ──MCP/stdio──▶ MCP server ──localhost WebSocket──▶ Chrome extension ──▶ your real tab
(src/server) (extension/)
│
▼
human-path engine (src/path-engine)
from + to → timed cursor samples with overshoot, log-normal
velocity, jitter, off-center landing, dwell — fresh every callThe MCP server generates the cursor sample stream; the extension is a thin
replayer. The same stream works for the content-script driver, the
chrome.debugger stealth driver, and (phase 2) the OS cursor — they all
implement one BrowserDriver interface.
Why human-like movement is hard
Modern detectors (DataDome, Castle, reCAPTCHA v3, PerimeterX) flag overly smooth Bézier paths, constant velocity, dead-center clicks, zero dwell, teleporting jumps, and replayed identical paths. The engine addresses each:
Fitts's law sets per-move duration from distance and target size.
Asymmetric, eased velocity — not a symmetric min-jerk bell.
Overshoot-and-correct on long moves.
Sub-pixel Gaussian jitter, zero at the endpoints.
Off-center landing inside the target.
Right-skewed dwell before the press.
Per-call entropy — paths are never cached or replayed.
Realism is necessary but not sufficient: content-script events are
isTrusted=false, and chrome.debugger still leaks CDP tells. The real evasion
endgame is the phase-2 OS cursor (genuine, trusted OS events).
Install
git clone https://github.com/kumard3/agentcursor.git
cd agentcursor
pnpm install
pnpm build # builds dist/index.js + extension/dist/*Install as a Claude Code plugin (one step)
AgentCursor ships as a Claude Code plugin that registers the MCP server for you:
claude plugin marketplace add kumard3/agentcursor
claude plugin install agentcursorThat registers the agentcursor MCP server automatically (no manual claude mcp add). You still load the extension once (step 1 below). If you previously registered it by hand, remove that to avoid two servers fighting for the port: claude mcp remove agentcursor.
1. Load the extension
Open
chrome://extensions, enable Developer mode.Load unpacked → select the
extension/folder.Keep a normal
http(s)tab open and focused (notchrome://or the Web Store — content scripts can't run there).
2. Connect via MCP (agents, Cursor, Claude, custom tools, etc.)
Claude Code / Claude Desktop:
claude mcp add agentcursor -- node /absolute/path/to/agentcursor/dist/index.jsCursor, Windsurf, or any MCP-capable coding environment:
Add to your MCP servers config (exact format depends on the host):
{
"mcpServers": {
"agentcursor": {
"command": "node",
"args": ["/absolute/path/to/agentcursor/dist/index.js"]
}
}
}Any other MCP client (including future Grok harnesses, custom agents, test runners that speak MCP) — just point it at the stdio server the same way.
The server exposes the WebSocket bridge on ws://127.0.0.1:8930 (override with AGENTCURSOR_WS_PORT). The extension auto-reconnects.
3. Programmatic SDK (import { AgentCursor })
Drive the human cursor from your own Node/TS code with a Playwright-shaped locator API — no MCP client needed. Same engine, same stealth; every action moves a real cursor.
import { AgentCursor } from "agentcursor";
// Attach to a running Chrome that has the extension loaded.
// Pass { stealth: true } for trusted CDP events; use AgentCursor.os() for the nut-js OS cursor.
const ac = await AgentCursor.connect();
await ac.navigate("https://example.com");
await ac.getByRole("button", { name: "Buy now" }).click();
await ac.getByLabel("Email").fill("a@b.com");
await ac.getByText("Submit").click();
await ac.getByLabel("Email").press("Enter");
// chaining + filtering, just like Playwright
await ac.locator(".row").filter({ hasText: "Pro" }).nth(0).getByText("Edit").click();
if (await ac.getByTestId("checkout").isVisible()) {
await ac.getByTestId("checkout").click();
}
await ac.screenshot({ path: "out.png" });
await ac.close();Lifecycles
AgentCursor.connect({ port?, stealth?, timeoutMs? })— attach to a running Chrome with the extension loaded (works with your real, logged-in profile).AgentCursor.os({ stealth?, ... })— same locator API, but the real OS cursor is moved via nut-js (genuinely trusted events); page sensing still goes through the extension.launch()(spawn Chrome for you) is planned for a later release. Stable Chrome dropped--load-extensionin v137, so launch will target Chrome for Testing.
Locators (lazy, chainable, Playwright-shaped)
Find:
locator(css),getByRole(role, { name }),getByText,getByLabel,getByPlaceholder,getByTestId.Refine:
.filter({ hasText }),.nth(i),.first(),.last(), and chaining (a.locator(b)).Act:
.click(),.dblclick(),.hover(),.type(),.fill(),.press(key),.dragTo(other),.scrollIntoView().Query:
.boundingBox(),.textContent(),.isVisible(),.count(),.waitFor({ state }).
Each action resolves the locator in the page (role/label/etc. via @testing-library/dom, css/text via the DOM), then drives the human-path engine to the element. ac.actions exposes the lower-level ActionService (move by coords, find, clickText, scroll) as an escape hatch.
A full runnable example is in examples/sdk-quickstart.mjs; pnpm smoke:sdk runs the end-to-end pipeline against a simulated browser.
Note: in-page (
stealth: false) events areisTrusted=false. Usestealth: true(CDP) orAgentCursor.os()when you need trusted events.
Tools (MCP)
Tool | What it does |
| Interactive elements with stable |
| Identification: locate elements by their visible text / accessible name (shadow-DOM aware). Returns ranked |
| Identification + interaction in one step: find the best text match and human-move + click it (re-reads if needed). Supports |
| Human-like path to a |
| Full human move + click (supports button, double, stealth mode for trusted events). |
| Human approach + hover events (mouseover/mouseenter). Critical for dropdowns, tooltips, nav, and realistic workflows. |
| Human path drag from ref/coords to target while holding button (sliders, reorder, canvas). |
| Human-timed keystrokes (auto human-clicks ref to focus if provided). |
| Press a single key (Enter, Escape, Tab, arrows, Home/End, PageUp/Down, Space, or a character) on the focused element. content or stealth. |
| Eased, human-stepped scrolling. |
| Capture the visible tab as an image, scaled so 1 image pixel = 1 click coordinate — see the page, then |
| Load a URL in the active tab. |
| Current tab URL. |
| Wait for element ref or visible text (up to timeout). Use for resilient testing flows. |
| Health / connection status, driver, active URL, port. Great for CI, long-running workflows, and monitoring. |
Any driving action accepts stealth: true to deliver trusted events through the
chrome.debugger driver (this shows Chrome's "debugging this browser" banner).
Using as a Testing & Workflow Automation Tool
AgentCursor is not only for agents — it's a practical local browser automation primitive you can use directly in tests and scripts via MCP or by importing the core.
Why it shines for testing/automation on real sites:
Human cursor paths + dwell + jitter + off-center clicks make interactions look like a real person (useful when sites have light behavioral signals).
The visible cursor + overlay makes it excellent for demo videos, manual review of automation, and debugging failing flows.
screenshot+read_page+wait_for+hovergive you the primitives for visual + functional checks.Works against your real Chrome profile (cookies, extensions, logins) — perfect for realistic E2E that headless tools struggle with.
Example flow an agent or a test script might do:
read_page
hover "nav-menu"
click "Products"
wait_for text:"Featured"
screenshot
type {ref: "search", text: "laptop"}
click "search button"
...Direct / programmatic use (API style): The core ActionService, path engine, and drivers are designed to be importable. See "Programmatic Use" below.
Example: Using with Claude Code to post on X.com / Reddit
With the MCP integration, you can tell Claude Code (or Cursor) to use agentcursor for realistic posting/automation on real sites:
Have a logged-in tab open on x.com (or reddit.com).
Start the server (ideally with OS driver on mac for best results).
In Claude: "Add agentcursor MCP if not present, then use the tools to navigate to x.com if needed, read the page, hover and click the compose area, type a test post, screenshot for verification, and click the post button. Use human-like actions and wait_for as needed. Report status often."
The shadow DOM support (added in 0.2.0) helps surface elements inside X's web components. Combine with screenshot + status + loops of read_page / wait_for for resilience on SPAs.
See the testing section above for general flow patterns. Always start with status and read_page, use screenshot to ground the agent.
Trusted OS cursor (phase 2, macOS)
Content-script events are isTrusted=false, and chrome.debugger still leaks
CDP tells. For genuinely trusted, indistinguishable input, switch to the
OS-cursor driver, which moves the real macOS system cursor along the same human
path:
pnpm add @nut-tree-fork/nut-js # optional native dependency
AGENTCURSOR_DRIVER=os node dist/index.jsIt still reads the page through the extension (keep a normal tab focused), but every move/click/scroll becomes a real OS event. Requires the Chrome window visible and foregrounded at 100% zoom, and Accessibility permission for your terminal/Node in System Settings → Privacy & Security. Coordinate mapping for multi-monitor / fractional-scaling setups is still rough.
Known limitations
Content-script events are
isTrusted=false. For detection-sensitive sites passstealth: true(thechrome.debuggerdriver, trusted events) or use the OS-cursor driver. The visible overlay cursor shows in every mode.React-controlled inputs (X's composer, some design systems) can ignore content-script typing, which sets
valuedirectly. Usestealth: true(CDPInput.insertText) or the OS driver there.wait_forby text and the snapshottextfield useinnerText, which does not pierce shadow DOM.read_page's element list does traverse shadow roots, so prefer waiting on a[ref]over page text on web-component-heavy sites (X, Reddit).The OS-cursor driver assumes 100% browser zoom and a single display; multi-monitor and fractional scaling can be off.
hoverdispatches its hover events through the content script (the approach move is trusted understealth, the explicitmouseover/mouseenterare not).Content-mode
press_keycarrieskey/codebut not legacykeyCode— a constructedKeyboardEventalways reportskeyCode: 0. Modern handlers readkey; for sites that still checkkeyCode/which, usestealth: true(the CDP key event sets the real virtual key code).
Measuring realism
Serve the detector over http (the extension's content script only runs on
http(s), not file://):
python3 -m http.server 8080 --directory test-detectorOpen http://localhost:8080, click the targets by hand, then drive them with
the agent. Each click is scored on straightness, velocity variance, dwell,
off-center landing, overshoot, and isTrusted — the same features detectors
use. Use it to tune the engine.
Development
pnpm dev # run the server with tsx (no build)
pnpm typecheck # tsc --noEmit
pnpm test # vitest (path-engine + coord-map unit tests)
pnpm build:ext # rebuild just the extension (no version change)
pnpm reload # rebuild the extension AND patch-bump the version, so a chrome://extensions reload is visibly new
pnpm smoke # end-to-end run: real MCP client + server, simulated browser (now covers screenshot/hover/status too)The smoke script is also a good template for writing your own automation or test runners that drive AgentCursor over MCP.
Credits
The path engine builds on the ghost-cursor lineage (Bézier + Fitts) and the
mouse-dynamics literature — WindMouse, SapiAgent, BeCAPTCHA-Mouse, and the
vendor write-ups from DataDome and Castle on what makes synthetic movement
detectable. See docs/DESIGN.md.
License
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server + Chrome extension that gives AI coding agents control of your real browser with existing sessions, logins, and cookies. Works with Cursor, Claude, Windsurf.Last updated186747MIT
- Alicense-qualityDmaintenanceEnables real browser automation as tools in Cursor, Claude Desktop, Windsurf, and any MCP-compatible client, allowing AI agents to interact with web pages through natural language.Last updated10MIT
- Alicense-qualityDmaintenanceEnables browser automation through MCP clients like Claude or Cursor, using the client's existing LLM without requiring an additional API key.Last updatedApache 2.0
- Alicense-qualityBmaintenanceChrome extension + MCP bridge that gives Claude control over your real browser via CDP, enabling navigation, clicking, typing, scrolling, screenshots, and JS execution with a visible cursor and tab-bring-to-front.Last updated1MIT
Related MCP Connectors
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
A paid remote MCP for AI agent browser approval MCP, built to return verdicts, receipts, usage logs,
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kumard3/agentcursor'
If you have feedback or need assistance with the MCP directory API, please join our Discord server