pilot_click
Click any interactive element on a webpage using a reference from a snapshot or CSS selector. Supports left, right, or middle button clicks and double-clicks.
Instructions
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 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.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ref | Yes | Element ref (@e3) or CSS selector | |
| button | No | Mouse button | |
| double_click | No | Double-click instead of single click |
Implementation Reference
- src/tools/interaction.ts:19-96 (handler)The main handler for pilot_click tool registration and implementation. The function `registerInteractionTools` registers 'pilot_click' on the MCP server with Zod schema parameters (ref, button, double_click). The handler logic: (1) checks for extension mode, (2) auto-routes clicks on <option> elements to selectOption, (3) resolves the element ref and performs the click via Playwright's locator.click() or page.click(), (4) waits for load state, (5) returns confirmation with URL and snapshot, (6) catches errors with failure tracking.
export function registerInteractionTools(server: McpServer, bm: BrowserManager) { server.tool( 'pilot_click', `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.`, { ref: z.string().describe('Element ref (@e3) or CSS selector'), button: z.enum(['left', 'right', 'middle']).optional().describe('Mouse button'), double_click: z.boolean().optional().describe('Double-click instead of single click'), }, async ({ ref, button, double_click }) => { await bm.ensureBrowser(); try { const ext = bm.getExtension(); if (ext) { await bm.extSend('click', { ref, button, double_click }); bm.resetFailures(); const snap = await ext.send<{ text: string }>('snapshot', { maxElements: 20 }); return { content: [{ type: 'text' as const, text: `Clicked ${ref}\n--- page state ---\n${snap.text}` }] }; } const page = bm.getPage(); // Auto-route: if ref points to a <option>, use selectOption const role = bm.getRefRole(ref); if (role === 'option') { const resolved = await bm.resolveRef(ref); if ('locator' in resolved) { const optionInfo = await resolved.locator.evaluate(el => { if (el.tagName !== 'OPTION') return null; const option = el as HTMLOptionElement; const select = option.closest('select'); if (!select) return null; return { value: option.value, text: option.text }; }); if (optionInfo) { await resolved.locator.locator('xpath=ancestor::select').selectOption(optionInfo.value, { timeout: 5000 }); bm.resetFailures(); const snap = await postActionSnapshot(bm); return { content: [{ type: 'text' as const, text: `Selected "${optionInfo.text}" (auto-routed from click on <option>) → now at ${page.url()}${snap}` }] }; } } } const resolved = await bm.resolveRef(ref); const clickOptions: any = { timeout: 5000 }; if (button) clickOptions.button = button; if (double_click) clickOptions.clickCount = 2; if ('locator' in resolved) { await resolved.locator.click(clickOptions); } else { await page.click(resolved.selector, clickOptions); } await page.waitForLoadState('domcontentloaded').catch(() => {}); bm.resetFailures(); const snap = await postActionSnapshot(bm); return { content: [{ type: 'text' as const, text: `Clicked ${ref} → now at ${page.url()}${snap}` }] }; } catch (err) { bm.incrementFailures(); const hint = bm.getFailureHint(); let msg = wrapError(err); if (hint) msg += '\n' + hint; return { content: [{ type: 'text' as const, text: msg }], isError: true }; } } ); - src/tools/interaction.ts:36-40 (schema)Zod input schema for pilot_click: 'ref' (string, required - element ref like @e3 or CSS selector), 'button' (optional enum: left/right/middle), 'double_click' (optional boolean).
{ ref: z.string().describe('Element ref (@e3) or CSS selector'), button: z.enum(['left', 'right', 'middle']).optional().describe('Mouse button'), double_click: z.boolean().optional().describe('Double-click instead of single click'), }, - src/tools/register.ts:21-31 (registration)pilot_click is registered in the CORE_TOOLS set (line 25), making it available in all tool profiles: core, standard, and full. It's one of the 9 most essential tools.
const CORE_TOOLS = new Set([ 'pilot_navigate', 'pilot_snapshot', 'pilot_snapshot_diff', 'pilot_click', 'pilot_fill', 'pilot_type', 'pilot_press_key', 'pilot_wait', 'pilot_screenshot', ]);