click
Click webpage elements by id, visible text, or CSS selector. Returns whether the click had an effect based on pre/post screenshot diff, helping verify interactions.
Instructions
Click by id (from inspect), by visible text, or by CSS selector. Returns {changed: true/false} based on a pre/post screenshot diff — false means the click had no effect.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | ||
| text | No | ||
| selector | No |
Implementation Reference
- src/index.ts:250-285 (handler)The click tool handler function. Accepts optional id (from inspect), text (visible text), or selector (CSS). Takes a pre-click screenshot, performs the click (via data-helm-id, CSS selector, getByText, or getByRole fallback), then takes a post-click screenshot to determine if the page changed. Returns {url, changed}.
async function click(args: { id?: number; text?: string; selector?: string }) { const p = requirePage(); const before = await p.screenshot({ type: 'png' }); if (args.id !== undefined) { // Auto-retag if we don't see any helm ids yet (e.g. user called click before inspect). const tagged = await p.evaluate(() => document.querySelector('[data-helm-id]') !== null); if (!tagged) await tagInteractive(p); const loc = p.locator(`[data-helm-id="${args.id}"]`).first(); if ((await loc.count()) === 0) { throw new Error(`No element with helm id=${args.id}. Run inspect() first to refresh ids.`); } await loc.click({ timeout: 8000 }); } else if (args.selector) { await p.locator(args.selector).first().click({ timeout: 8000 }); } else if (args.text) { // Try text first, fall back to button-by-name. try { await p.getByText(args.text, { exact: false }).first().click({ timeout: 4000 }); } catch { await p.getByRole('button', { name: args.text }).first().click({ timeout: 4000 }); } } else { throw new Error('Provide one of: {id}, {text}, or {selector}.'); } // Best-effort wait for navigation/repaint. await p.waitForLoadState('domcontentloaded', { timeout: 5000 }).catch(() => {}); await p.waitForTimeout(150); const after = await p.screenshot({ type: 'png' }); return { url: p.url(), changed: !before.equals(after), }; } - src/index.ts:386-399 (registration)Registration of the 'click' tool in the TOOLS array declared for ListToolsRequestSchema. Defines the tool name, description, and inputSchema (id, text, selector as optional properties).
{ name: 'click', description: 'Click by id (from inspect), by visible text, or by CSS selector. Returns ' + '{changed: true/false} based on a pre/post screenshot diff — false means the click had no effect.', inputSchema: { type: 'object', properties: { id: { type: 'number' }, text: { type: 'string' }, selector: { type: 'string' }, }, }, }, - src/index.ts:466-472 (handler)Dispatch/call-site in the CallToolRequestSchema handler where the 'click' tool name is routed to the click() function.
case 'click': result = await click(args as { id?: number; text?: string; selector?: string }); break; case 'type': result = await type(args as { text: string; id?: number; selector?: string; submit?: boolean }); break; case 'navigate': result = await navigate(args as { url: string }); break; case 'wait_for': result = await waitFor(args as { text?: string; selector?: string; timeoutMs?: number }); break; case 'handoff': result = await handoff(args as { reason: string }); break; default: throw new Error(`Unknown tool: ${name}`); }