pilot-mcp — Fast Browser Automation MCP Server
@TacosyHorchata
About pilot-mcp — Fast Browser Automation MCP Server
Fast browser automation MCP server. In-process Playwright, 58 tools (profiles: 9/28/58), cookie import from Chrome/Arc/Brave, handoff/resume for CAPTCHAs, iframe support, snapshot diffing. 41% faster than @playwright/mcp.
Config
Add this server to your MCP-compatible client using the configuration below.
{
"mcpServers": {
"pilot": {
"command": "npx",
"args": [
"-y",
"pilot-mcp"
]
}
}
}Tools
30Navigate the browser to a URL and wait for DOM content to load. Use when the user wants to go to a specific webpage, URL, or link. For read tasks ("go to X and tell me Y"), prefer pilot_get — it returns full readable content + interactive elements in one call, eliminating a follow-up snapshot call. Parameters: - url: The URL to navigate to (e.g., "https://example.com" or relative paths) Returns: Confirmation message with the HTTP status code, content preview, and interactive elements. Errors: - "Invalid URL": The URL format is malformed. Provide a complete URL including the protocol. - Timeout (15s): The page took too long to load. Try pilot_navigate again or check the URL. - "Navigation denied": The URL was rejected by security validation (e.g., file:// on restricted origins).
Navigate back to the previous page in browser history. Use when the user wants to go back to the prior page they visited. Parameters: (none) Returns: The URL of the page after navigating back. Errors: - "No previous page in history": There is nothing to go back to. Use pilot_navigate instead. - Timeout (15s): The previous page took too long to load.
Navigate forward to the next page in browser history. Use when the user wants to go forward after using pilot_back. Parameters: (none) Returns: The URL of the page after navigating forward. Errors: - "No next page in history": There is nothing to go forward to. Use pilot_navigate instead. - Timeout (15s): The next page took too long to load.
Reload the current page, waiting for DOM content to load. Use when the user wants to refresh the page, clear dynamic state, or retry a failed load. Parameters: (none) Returns: The URL of the reloaded page. Errors: - Timeout (15s): The page took too long to reload. Try again or check network connectivity.
Navigate to a URL and return its full readable content + interactive elements in one call. Use this as the primary tool for "go to X and find Y" read tasks. It combines navigation and content extraction, eliminating the need for a separate snapshot call. Parameters: - url: The URL to fetch Returns: Page title, readable body text (up to 1500 chars), and interactive elements. Enough context to answer most read questions without additional tool calls. Errors: - Timeout (15s): The page took too long to load.
Capture an accessibility tree snapshot of the page with @eN refs for element selection. Use when the user wants to see the page structure, find elements to interact with, or get refs for click/fill/hover. This is the primary way to understand what is on the page. Refs from this snapshot are used by pilot_click, pilot_fill, pilot_hover, pilot_select_option, and most other interaction tools. Parameters: - selector: CSS selector to scope the snapshot to a specific subtree (e.g., "#main-content") - interactive_only: Set to true to show only interactive elements (buttons, links, inputs) — saves tokens on large pages - compact: Set to true to remove empty structural nodes from the tree - depth: Limit the tree depth (0 = root only). Useful for reducing token usage on deeply nested pages - include_cursor_interactive: Set to true to scan for elements with cursor:pointer, onclick, or tabindex that are not in the ARIA tree — returns @cN refs - max_elements: Maximum elements to include before truncating (saves tokens on very large pages) - structure_only: Set to true to show tree structure without text content — saves tokens when you only need the element hierarchy - output_file: Set to true to save the snapshot to a temp file instead of returning inline. Returns the file path — read with the Read tool when needed. Useful when the snapshot is large and you only need it on demand. Returns: Text representation of the accessibility tree with @eN refs (and @cN refs if include_cursor_interactive is true). If output_file=true: returns only the file path (e.g. /tmp/pilot-snap-abc123.txt). Errors: - Timeout: The page is too complex or unresponsive. Try scoping with selector or using max_elements.
Compare the current page state against the previously captured snapshot, showing a unified diff of what changed. Use when the user wants to verify the effect of an action (click, fill, navigation), check if dynamic content loaded, or see what changed on the page without re-reading the entire snapshot. The first call stores a baseline; subsequent calls diff against it. Parameters: - selector: CSS selector to scope both snapshots to a specific subtree - interactive_only: Set to true to only diff interactive elements (buttons, links, inputs) Returns: Unified diff text showing added (+) and removed (-) lines between snapshots. Errors: - "No baseline snapshot": This is the first call — a baseline will be stored for future diffs. - Timeout: The page is unresponsive.
Find an element by visible text, label, placeholder, or role — without running a full snapshot. Use when you know what you want to click or fill but don't need to see the entire page tree. Returns a @eN ref immediately usable by pilot_click, pilot_fill, pilot_hover, and other interaction tools. Saves tokens compared to pilot_snapshot when you only need one element. Parameters: - text: Visible text content of the element (e.g., "Sign in", "Submit") - label: ARIA label or associated <label> text (e.g., "Email address", "Password") - placeholder: Input placeholder text (e.g., "Search...", "Enter email") - role: ARIA role to match (e.g., "button", "link", "textbox") — combine with text for precision - exact: Set to true for exact text/label match (default: false, substring match) Returns: A @eN ref for the found element and a description of what was found. Errors: - "Element not found": No element matched the criteria. Verify the text/label or run pilot_snapshot to inspect the page. - "Multiple elements found": More than one element matched. Add role or use exact=true to narrow it down.
Take a PNG screenshot with red overlay boxes and ref labels at each @eN/@cN element position. Use when the user wants a visual debug overlay showing where each snapshot ref is located on the page, or needs to verify element positions visually. Requires a prior pilot_snapshot call to populate the ref positions. For a clean visual capture without debug overlays, use pilot_screenshot instead. Parameters: - output_path: Optional file path to save the annotated screenshot (default: temp directory) Returns: The annotated screenshot as a base64 PNG image and the file path where it was saved. Errors: - "No ref positions": Run pilot_snapshot first to capture element positions before taking an annotated screenshot. - Timeout: The page is unresponsive.
Click an element on the page using a ref from pilot_snapshot or a CSS selector. Use when the user wants to press a button, follow a link, check a checkbox, or interact with any clickable element. Auto-routes clicks on <option> elements to pilot_select_option. Parameters: - ref: Element reference from snapshot (e.g., "@e3") or a CSS selector (e.g., "button.submit") - button: Mouse button to click — "left" (default), "right" (context menu), or "middle" - double_click: Set to true for a double-click instead of single click Returns: Confirmation with the clicked ref and the current URL after navigation (if any). Errors: - "Element not found": The ref is stale or the selector matches nothing. Run pilot_snapshot to get fresh refs. - "Element is not clickable": The element exists but is obscured or disabled. Try scrolling to it first with pilot_scroll. - "Timeout": The click triggered a navigation that took too long. The page may still be loading.
Hover the mouse over an element, triggering hover states, tooltips, and dropdown menus. Use when the user wants to reveal hidden content, trigger a CSS :hover effect, or inspect tooltip text. Parameters: - ref: Element reference from snapshot (e.g., "@e7") or a CSS selector Returns: Confirmation with the hovered element ref. Errors: - "Element not found": The ref is stale. Run pilot_snapshot to get fresh refs. - Timeout (5s): The element could not be hovered — it may be off-screen or detached.
Fill an input or textarea with new text, replacing any existing content. Use when the user wants to enter text into a form field, search box, or editable element. Prefer pilot_fill over pilot_type for inputs because it is faster and clears existing content automatically. Parameters: - ref: Element reference from snapshot (e.g., "@e12") or a CSS selector (e.g., "#email") - value: The text to fill into the element Returns: Confirmation with the filled element ref. Errors: - "Element not found": The ref is stale. Run pilot_snapshot to get fresh refs. - "Element is not editable": The element is read-only or disabled. Try pilot_click to enable it first. - Timeout (5s): The element could not be filled.
Select an option from a <select> dropdown element by value, label, or visible text. Use when the user wants to choose a dropdown option, select from a combobox, or pick from a list. Note: clicking an <option> in pilot_snapshot is auto-routed here. Parameters: - ref: The <select> element reference from snapshot (e.g., "@e5") or a CSS selector - value: The option's value attribute, label, or visible text to match Returns: Confirmation with the selected value and element ref. Errors: - "No option matched": The value does not match any option. Check the exact option text or value attribute via pilot_page_html. - "Element not found": The ref is stale or does not point to a <select> element. Run pilot_snapshot.
Type text character-by-character into the currently focused element, simulating real keyboard input. Use when the user wants to type into a contenteditable div, rich text editor, or a field that reacts to individual keystrokes (e.g., autocomplete, keypress events). For standard <input>/<textarea> elements, prefer pilot_fill which is faster. Parameters: - text: The text string to type - submit: Set to true to press Enter after typing (useful for search fields and forms) Returns: Character count typed and whether Enter was pressed. Errors: - "No element is focused": Nothing is focused on the page. Use pilot_click on the target field first. - Timeout: The page became unresponsive during typing.
Press a keyboard key or key combination on the page. Use when the user wants to press Enter to submit a form, Tab to move between fields, Escape to close a modal, ArrowDown to navigate a list, or use any keyboard shortcut. Parameters: - key: Key name or combination (e.g., "Enter", "Tab", "Escape", "ArrowDown", "Backspace", "Shift+Enter", "Control+a") Returns: Confirmation of the key pressed. Errors: - "Unknown key": The key name is not recognized. Use standard Playwright key names (see docs.playwright.dev/key-input).
Drag one element and drop it onto another element on the page. Use when the user wants to move an element, reorder items in a drag-and-drop list, or interact with a drag-and-drop UI. Parameters: - start_ref: The source element reference from snapshot (e.g., "@e3") or CSS selector to drag from - end_ref: The target element reference from snapshot (e.g., "@e5") or CSS selector to drop onto Returns: Confirmation with source and target refs. Errors: - "Element not found": Either ref is stale. Run pilot_snapshot to get fresh refs. - Timeout (5s): The drag operation could not be completed. The elements may not support drag-and-drop.
Scroll the page or a specific element into view. Use when the user wants to scroll down a long page, scroll to the bottom, scroll to the top, or scroll a specific element into the viewport. With a ref, scrolls the element into view. Without a ref, scrolls the page by one viewport height or to a specific position. Parameters: - ref: Element reference from snapshot (e.g., "@e20") or CSS selector to scroll into view (omit for page scroll) - direction: Page scroll direction when no ref is provided — "up", "down", "top", or "bottom" (default: "bottom") Returns: Confirmation of what was scrolled and in which direction. Errors: - "Element not found": The ref is stale. Run pilot_snapshot to get fresh refs. - Timeout (5s): The element could not be scrolled into view.
Wait for a specific condition before proceeding — an element to appear, the network to become idle, or the page to finish loading. Use when the user wants to wait for a dynamic element to load, wait for AJAX/fetch requests to complete, or wait for a modal/spinner to appear or disappear. Parameters: - ref: Element reference from snapshot (e.g., "@e10") or CSS selector to wait for - state: What to wait for — "visible" (element appears, default), "hidden" (element disappears), "networkidle" (no network requests for 500ms), or "load" (page load event) - timeout: Maximum wait time in milliseconds (default: 15000) Returns: Confirmation of what was waited for and its state. Errors: - "Timeout waiting for element": The element did not reach the expected state in time. Increase timeout or check the selector. - "Nothing to wait for": Neither ref nor state was provided. Supply at least one.
Extract clean text from the page (strips script/style/noscript/svg).
Get innerHTML of a selector/ref, or full page HTML if none provided.
Take a PNG screenshot of the current page or a specific element. Use when the user wants to capture what the page looks like visually, save a screenshot to disk, or capture a specific element's appearance. For a visual debug overlay with ref labels, use pilot_annotated_screenshot instead. Parameters: - ref: Element reference from snapshot (e.g., "@e3") or CSS selector to screenshot a specific element (omit for full page) - full_page: Set to false for viewport-only capture (default: true, captures the entire scrollable page) - output_path: File path to save the screenshot (default: /tmp/pilot-screenshot.png). Must be within the allowed output directory - clip: Crop region as {x, y, width, height} pixel coordinates for a specific area of the page Returns: The screenshot as a base64 PNG image and the file path where it was saved. Errors: - "Output path must be within ...": The path is outside the allowed directory. Set PILOT_OUTPUT_DIR or use /tmp. - "Element not found": The ref is stale. Run pilot_snapshot to get fresh refs.
List all open browser tabs with their IDs, URLs, titles, and which tab is currently active. Use when the user wants to see what tabs are open, find a specific tab by title or URL, or check which tab is active before switching. Parameters: (none) Returns: Numbered list of tabs showing [id], title, URL, and an arrow (→) marking the active tab. Errors: None — returns empty list if no tabs exist (unlikely in normal operation).
Open a new browser tab, optionally navigating to a URL. Use when the user wants to open a link in a new tab, create a blank tab, or work with multiple pages simultaneously. Parameters: - url: Optional URL to navigate to in the new tab (omit for a blank about:blank tab) Returns: The new tab's ID and URL (if provided). Errors: - "Invalid URL": The URL is malformed. Provide a complete URL with protocol.
Close a browser tab by its ID, or close the currently active tab if no ID is specified. Use when the user wants to close a popup, remove an unwanted tab, or clean up after finishing work in a tab. Parameters: - id: Tab ID to close (omit to close the current active tab). Use pilot_tabs to list tab IDs. Returns: Confirmation that the tab was closed. Errors: - "No such tab": The provided tab ID does not exist. Run pilot_tabs to see valid IDs. - "Cannot close last tab": The last remaining tab cannot be closed.
Switch the active browser context to a specific tab by its ID. Use when the user wants to work in a different tab, bring a background tab to the foreground, or continue automation in a previously opened tab. Use pilot_tabs to find tab IDs. Parameters: - id: The tab ID to switch to (from pilot_tabs output) Returns: Confirmation with the tab ID that is now active. Errors: - "No such tab": The provided tab ID does not exist. Run pilot_tabs to see valid IDs.
Save, load, or clear browser session state (cookies + localStorage + sessionStorage) to/from a JSON file. Use when the user wants to authenticate once and reuse credentials across sessions, skip re-login flows, or transfer session state between runs. Complement to pilot_import_cookies — use pilot_auth for Pilot-managed state, pilot_import_cookies for one-time import from a real browser. Parameters: - action: "save" — write current session to file; "load" — restore session from file; "clear" — clear cookies and storage from browser - path: File path to save or load (e.g., "~/.pilot/github.json"). Required for save/load actions. Returns: - save: Count of cookies saved and the file path. - load: Count of cookies restored. - clear: Confirmation that cookies and storage were cleared. Errors: - "Session file not found": The path does not exist. Run with action="save" first. - "Browser not launched": Navigate to a URL first to initialize the browser.
Block network requests matching URL patterns to speed up page loads and reduce token noise from ad/tracker content. Use when the user wants to block ads, trackers, analytics scripts, or any noisy domain. Blocked requests are aborted before they hit the network — faster loads, smaller snapshots. Use the built-in "ads" preset to block ~20 major ad networks with one call. Parameters: - patterns: Array of URL glob patterns to block (e.g., ["*googletag*", "*.hotjar.com/*"]) - preset: Built-in preset to block — "ads" blocks ~20 major ad and tracker networks - clear: Set to true to remove all active blocks Returns: - Add mode: List of active blocked patterns. - clear mode: Confirmation that all blocks were removed. Errors: None — invalid patterns are silently ignored by the browser.
List all frames (iframes) on the current page with their indices, names, and URLs. Use when the user wants to see what iframes exist on the page, find an iframe to interact with, or verify the page structure before switching frame context. The main frame is always index 0. Use pilot_frame_select to switch into an iframe. Parameters: (none) Returns: Numbered list of frames showing index, type ([main] or [iframe name="..."]), URL, and an arrow (→) marking the currently active frame. Returns "(no iframes — only the main frame)" if no iframes exist. Errors: None.
Switch the browser context into an iframe so that pilot_snapshot, pilot_click, pilot_fill, and other tools operate inside that frame instead of the main page. Use when the user wants to interact with elements inside an embedded iframe, read iframe content, or fill forms within an iframe. After switching, all refs are cleared — run pilot_snapshot to get fresh refs for the iframe contents. Use pilot_frames to list available frames first. Parameters: - index: Frame index number from pilot_frames output (e.g., 1, 2) - name: Frame name attribute (alternative to index) Returns: Confirmation with the frame index/name and its URL, plus a reminder to run pilot_snapshot for fresh refs. Errors: - "Frame not found": The index or name does not match any frame. Run pilot_frames to see valid indices and names. - "Provide index or name": Neither parameter was supplied.
Switch the browser context back to the main page frame after working inside an iframe. Use when the user wants to return to the main page after interacting with an iframe. All refs are cleared — run pilot_snapshot to get fresh refs for the main page content. Parameters: (none) Returns: Confirmation of switching to the main frame, with a reminder to run pilot_snapshot. Errors: None — always succeeds.
Overview
What is pilot-mcp?
pilot-mcp is an MCP server that gives AI agents like Claude Code and Cursor a fast, persistent browser for web automation. Built on Playwright, it runs Chromium in-process over stdio, achieving ~5-50ms latency per action after the initial 3s launch — claimed to be 20x faster than alternatives.
How to use pilot-mcp?
Install with npx pilot-mcp and run npx playwright install chromium. Add a server entry to your Claude Code .mcp.json or Cursor MCP settings with command: "npx" and args: ["-y", "pilot-mcp"]. Environment variable PILOT_PROFILE selects tool set: core (9 tools), standard (25, default), or full (51 tools).
Key features of pilot-mcp
- 51 tools for navigation, snapshots, interaction, iframes, and debugging.
- Snapshot‑by‑ref system: capture once, interact using
@eNrefs. - Token control:
max_elements,structure_only,interactive_onlyfilters. - Cookie import from Chrome, Arc, Brave, Edge, and Comet.
- Handoff/resume: open headed Chrome, interact manually, then resume automation.
- Snapshot diffing to track page changes between actions.
Use cases of pilot-mcp
- Multi‑step web research: navigate, click, read results across several pages.
- Form filling and data extraction with structured snapshots.
- Testing UI workflows across tabs, iframes, and dialogs.
- Comparing page content (staging vs production) via
pilot_page_diff. - Debugging: inspect console logs, network requests, and element state in real time.
FAQ from pilot-mcp
What runtime does pilot-mcp require?
Node.js, Playwright, and Chromium (installed via npx playwright install chromium). No HTTP server or Chrome extension needed; everything runs over stdio.
How does pilot-mcp compare to @playwright/mcp or BrowserMCP?
pilot-mcp claims ~5-50ms per action vs 100-300ms for alternatives, with a persistent in‑process browser, 51 tools, cookie import, iframe support, and token‑control filters that alternatives lack.
Can I use my existing browser cookies?
Yes. pilot_import_cookies decrypts cookie databases from Chrome, Arc, Brave, Edge, and Comet using platform‑specific safe storage keys.
What security protections are built in?
Output path validation restricts screenshots/PDFs to PILOT_OUTPUT_DIR, path traversal is blocked, pilot_evaluate input is limited to 50KB, and file uploads resolve symlinks to prevent directory escape.
Does pilot-mcp support authentication?
No built‑in authentication. Cookie import can forward logged‑in sessions from your real browser, and custom headers (pilot_set_header) can be used for API keys or tokens.
Frequently asked questions
What runtime does pilot-mcp require?
Node.js, Playwright, and Chromium (installed via `npx playwright install chromium`). No HTTP server or Chrome extension needed; everything runs over stdio.
How does pilot-mcp compare to @playwright/mcp or BrowserMCP?
pilot-mcp claims ~5-50ms per action vs 100-300ms for alternatives, with a persistent in‑process browser, 51 tools, cookie import, iframe support, and token‑control filters that alternatives lack.
Can I use my existing browser cookies?
Yes. `pilot_import_cookies` decrypts cookie databases from Chrome, Arc, Brave, Edge, and Comet using platform‑specific safe storage keys.
What security protections are built in?
Output path validation restricts screenshots/PDFs to `PILOT_OUTPUT_DIR`, path traversal is blocked, `pilot_evaluate` input is limited to 50KB, and file uploads resolve symlinks to prevent directory escape.
Does pilot-mcp support authentication?
No built‑in authentication. Cookie import can forward logged‑in sessions from your real browser, and custom headers (`pilot_set_header`) can be used for API keys or tokens.
Basic information
More Browser Automation MCP servers

HTML/CSS to Image
An MCP server for generating images from HTML & CSS or screenshots of URLs using htmlcsstoimage.com.

Parse
Parse.botParse allows your agent to access thousands of APIs instantly. You can use Parse to build an API for any action on any website and edit any previously existing API in our catalogue.
Yoyo
firecrawl🔥 Official Firecrawl MCP Server - Adds powerful web scraping and search to Cursor, Claude and any other LLM clients.
mcp-browser-use: MCP server for browser-use
vinayak-mehtaMCP server for browser-use
MCP server w/ Browser Use
JovaniPinkFastAPI server implementing MCP protocol Browser automation via browser-use library.
Comments