Skip to main content
Glama

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

TableJSON Schema
NameRequiredDescriptionDefault
refYesElement ref (@e3) or CSS selector
buttonNoMouse button
double_clickNoDouble-click instead of single click

Implementation Reference

  • 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 };
          }
        }
      );
  • 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'),
    },
  • 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',
    ]);
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It discloses double-click capability, mouse button choices, return value (confirmation with ref and URL), and three specific errors with causes and remedies. Comprehensive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured: purpose first, then usage context, parameter details, return value, and errors. No redundant sentences, each sentence serves a purpose. Appropriately sized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 3 parameters, no output schema, no annotations, the description covers all necessary aspects: purpose, usage, parameters, return, errors, and sibling routing. Complete and actionable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but description adds value beyond schema: explains ref can be from snapshot or CSS selector with examples, clarifies button enum values, and describes double_click effect. Adds parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Click an element on the page using a ref from pilot_snapshot or a CSS selector.' It specifies the action (click) and resource (element). Mentions auto-routing for <option> to pilot_select_option, distinguishing from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use: 'when the user wants to press a button, follow a link, check a checkbox...' Also hints at alternatives via errors (e.g., use pilot_scroll for non-clickable elements). Lacks explicit when-not-to-use statements.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/TacosyHorchata/Pilot'

If you have feedback or need assistance with the MCP directory API, please join our Discord server