Latch
Allows AI agents to control an existing Google Chrome/Chromium browser profile through a local background service and browser extension. Supports navigation, tab and session management, accessibility snapshots, screenshots, clicking, filling, typing, scrolling, dragging, waiting, JavaScript evaluation, and direct Chrome DevTools Protocol commands.
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., "@LatchOpen a new tab to example.com and take an accessibility 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.
Latch
Latch lets AI agents control an existing Chromium browser profile through a local background service and a browser extension.
The browser extension executes commands via Chrome DevTools Protocol (chrome.debugger), and the Node.js background service routes requests from HTTP and MCP (Model Context Protocol) over a WebSocket connection.
Agent (AI / Script)
MCP stdio | POST /run | POST /command
│
▼
Latch Service (Node.js) 127.0.0.1:12580
│ WebSocket
▼
Latch Extension (Chrome / Chromium)
│ chrome.debugger (CDP)
▼
Browser TabsQuick Start
1. Requirements
Node.js 22 or later (or Docker)
pnpm
Google Chrome or any Chromium-based browser
2. Start the Background Service
Option 1: Run instantly with npx (zero clone/install)
# Start background HTTP service on 127.0.0.1:12580
npx github:p3psi-boo/latch start
# Or start with MCP stdio support (e.g. for AI agent clients)
npx github:p3psi-boo/latch mcpOption 2: Using Docker
docker run -d --name latch-server -p 12580:12580 ghcr.io/p3psi-boo/latch:latest
# or with docker compose:
docker compose up -dOption 3: Run from source
pnpm install
pnpm build
pnpm --filter @latch/daemon start # Listens on 127.0.0.1:125803. Install the Browser Extension
From GitHub Release / Artifact: Download
latch-extension.zipfrom Releases or CI artifacts, and unzip it.Or build from source:
pnpm build:extension # builds to packages/extension/dist
In Chrome / Chromium:
Open
chrome://extensionsin your browser.Enable Developer mode in the top right.
Click Load unpacked and select the unzipped directory (or
packages/extension/dist).The extension icon in the toolbar indicates connection to the background service.
Related MCP server: chrome-devtools-mcp
Usage
Option A: Model Context Protocol (MCP)
Start the service with MCP stdio support:
pnpm --filter @latch/daemon mcpExample Configuration
Claude Code / Cursor / Other MCP Clients:
{
"mcpServers": {
"latch": {
"command": "npx",
"args": ["github:p3psi-boo/latch", "mcp"]
}
}
}Pin to a specific Browser ID:
If you run multiple Chrome profiles and want this MCP server to only interact with a specific browser, add --browser <id>:
{
"mcpServers": {
"latch": {
"command": "npx",
"args": ["github:p3psi-boo/latch", "mcp", "--browser", "work"]
}
}
}(When pinned, the AI will automatically use this browser profile without needing to pass the browser argument in every tool call).
(Or use local repository command: "command": "pnpm", "args": ["--filter", "@latch/daemon", "mcp", "--", "--browser", "work"])
Grok (.grok/config.toml):
[mcp_servers.latch]
command = "npx"
args = ["github:p3psi-boo/latch", "mcp", "--browser", "work"]Option B: HTTP API
The background service exposes the following endpoints on http://127.0.0.1:12580:
Method | Endpoint | Request Body | Description |
|
|
| Forwards a script to the plugin sandbox |
|
|
| Executes a single browser command directly |
|
|
| Remote MCP endpoint over HTTP POST (auto-resolves browser) |
|
|
| Remote MCP endpoint pinned directly to |
|
| None | Returns connected browsers and active sessions |
|
| None | WebSocket connection used by the browser extension |
Authentication & Remote MCP Tips:
Pin Browser via Path: Connect directly to
http://127.0.0.1:12580/mcp/workto lock interactions to theworkbrowser.Token Protection: Start the daemon with
--token <secret>(orLATCH_TOKEN=<secret>). Then authenticate via query param?token=<secret>or headerAuthorization: Bearer <secret>.Example URL:
http://127.0.0.1:12580/mcp/work?token=your_secret_here
Example: Running an automation script (POST /run)
The script runs in an isolated plugin page with a separate Web Worker per invocation. The daemon only forwards requests; the plugin provides page and cliLog:
curl -s -X POST http://127.0.0.1:12580/run \
-H 'Content-Type: application/json' \
-d '{
"session": "search-task",
"source": "await page.goto(\"https://example.com\", { newTab: true, group_title: \"Latch Demo\" });\ncliLog(await page.snapshot());"
}'Available page helper methods:
Navigation & Tabs:
goto,findTab,listTabs,closeTab,closeSessionInspection:
snapshot(accessibility tree),screenshot,evaluateInteractions:
click,fill,selectOption,type,scroll,drag,waitLow-level:
cdp
For native dropdowns, use await page.selectOption('select[name="my-select"]', {label:"Two"}). Each match specifies exactly one of value, exact label, or zero-based index. An array replaces a multiple select's selection; [] clears it. The extension rejects missing, ambiguous, or disabled options, sets DOM selection, dispatches untrusted input/change events when the selection changes, and verifies the selected options after synchronous handlers. The result includes verified, mode:"dom", changed, values, and labels; asynchronous page updates and form submission require separate checks. Custom dropdown widgets retain their own click or keyboard sequence. The single MCP tool select_option uses the same implementation with selector and option parameters.
click rejects targets without a usable layout box. Its success and dispatched fields confirm mouse event dispatch, not the page's business outcome.
Example: Running a single command (POST /command)
Useful for quick testing and debugging:
curl -s -X POST http://127.0.0.1:12580/command \
-H 'Content-Type: application/json' \
-d '{
"session": "search-task",
"action": "navigate",
"args": { "url": "https://example.com" }
}'Supported actions:
navigate, find_tab, list_tabs, close_tab, close_session, snapshot, click, fill, select_option, type, scroll, drag, wait, screenshot, evaluate, cdp.
The plugin defines tools and the daemon relays requests.
packages/extension/src/tool-definitions.ts and tool-schemas.ts own MCP names, descriptions, and input schemas; tools.ts owns browser actions. The plugin publishes its definitions on connection. The daemon answers tools/list from those definitions and forwards calls to the selected plugin. Reconnects and definition updates generate notifications/tools/list_changed; HTTP clients can receive notifications through a GET SSE stream on the MCP endpoint and must refresh their tool list.
This migration uses wire protocol 2 and initially requires updating both packages. Run pnpm build, start the daemon with node bin/latch.cjs start, and load packages/extension/dist in Chrome with developer mode enabled. After replacing an unpacked plugin, click Reload on the extensions page. Set the plugin WebSocket URL to the daemon's /ws endpoint and connect MCP clients to /mcp/<browser-id>. Old-wire plugins are rejected. After this initial migration, browser tools can be added by upgrading only the plugin while the wire protocol remains compatible.
Scripts can invoke newly added tools with await page.call("tool_name", {arguments}); existing helpers such as page.selectOption(...) remain. The daemon no longer executes source or stores tab ownership. Plugin sessions use chrome.storage.session, surviving service worker restarts and daemon reconnects but not plugin reloads or browser shutdown. Chrome 116+ and the offscreen permission are required. Each script worker and its sandbox iframe are removed on completion or at the existing script deadline.
MCP screenshots return image content. HTTP commands and plugin scripts return mimeType and base64 image bytes instead of host file paths; clients save the image. On an unpinned endpoint, same-name tools from different plugins must have identical definitions. Use /mcp/<browser-id> when definitions differ. An unpinned endpoint lists no tools without a connected plugin; a pinned endpoint reports a connection error.
Working with Multiple Browsers
If you run multiple browser profiles simultaneously:
Right-click the Latch extension icon and open Options.
Configure the settings:
Browser ID: Unique identifier for this profile (optional, defaults to an auto-generated ID).
Remark: A readable description (e.g.
workorpersonal) shown in/statusand MCP.WebSocket URL: Defaults to
ws://127.0.0.1:12580/ws.
In your API requests, pass
"browser": "<browser-id>"when targeting a specific browser profile. If only one browser is connected, this field can be omitted.
Check connected browsers anytime:
curl -s http://127.0.0.1:12580/statusImportant Notes & Security
Network Access: By default, the service listens on
127.0.0.1:12580without authentication. Any program that can access this port can control connected browsers.Session Mapping: Each
sessionname corresponds to a Chrome tab group. Give sessions task-based names (such asresearch-topicororder-ticket).Input Simulation: Click and scroll actions dispatch standard pointer and keyboard events directly to the target page without rendering an artificial visual cursor.
Self-Hosting & Remote Access
To host the service on a remote machine:
Start the service with host binding and optional token:
# Single host (default: 127.0.0.1) latch start --host 127.0.0.1 --port 12580 # Or bind multiple specific IPv4 / IPv6 addresses: latch start --host "127.0.0.1, ::1, 2409:xxxx:xxxx::1" --port 12580 --token <secret>Put a reverse proxy with TLS (such as Caddy or Nginx) in front of it on port 443. Configuration templates are available in the
deploy/directory.In the extension settings, update the WebSocket URL to
wss://<your-domain>/ws.
Project Structure
Directory | Description |
| Shared message definitions, action names, and TypeScript interfaces |
| Background service implementation (HTTP API, WebSocket server, MCP server) |
| Manifest V3 Chrome extension executing browser actions |
| Production deployment configurations (systemd service, Caddyfile) |
| Prompting guidelines and tool usage reference for AI agents |
Development
# Run unit tests
pnpm test
# Rebuild extension
pnpm --filter @latch/extension buildLicense
This server cannot be deployed
Maintenance
Related MCP Connectors
Control a real browser from AI agents: navigate, click, type, screenshot, read the page.
Live browser debugging for AI assistants — DOM, console, network via MCP.
Official Browserless MCP server: browser automation, scraping, screenshots and PDFs for AI agents.
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Related MCP Servers
- FlicenseNot gradedqualityAmaintenanceEnables AI agents to control a persistent local browser with live tabs, navigation, interaction, inspection, and state management through MCP.6-
- AlicenseNot gradedqualityBmaintenanceEnables AI coding agents to control and inspect a live Chrome browser via MCP, including performance tracing, network and console debugging, screenshots, and reliable Puppeteer-based automation.1,737,496 npmApache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables remote AI agents to control a local, authenticated desktop browser over MCP through an outbound WebSocket bridge and Chrome extension, supporting tab management, navigation, page reading, clicking, typing, scrolling, screenshots, and JavaScript evaluation.1MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to see and control the user's real Chrome/Brave/Edge profile over MCP, so they can read pages, click, type, take screenshots, audit layouts, debug CSS, and scrape paginated or infinite-scroll data. Because it drives the normal browser via the DevTools protocol with real input events, it works on modern JavaScript apps and on sites where the user is logged in.12 npm1MIT