Click
pinchtab_clickClick an element by its reference ID using human-like mouse events. Optionally wait for navigation or return a page snapshot after a delay.
Instructions
Click an element by its ref ID (e.g. 'e5'). Uses human-like click by default. Set waitMs to get a snapshot after clicking (saves a round-trip). For SPAs, clicking may not cause full navigation.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| humanClick | No | Use real mouse events (default: true). Set to false for programmatic .click(). | |
| ref | Yes | Element reference ID (e.g. 'e5') | |
| waitMs | No | Wait this many ms after clicking, then return a compact page snapshot (max 10000). | |
| waitNav | No | Wait for navigation after click (useful for link clicks). Default: false. |
Implementation Reference
- src/tools/interaction.ts:7-49 (registration)The tool 'pinchtab_click' is registered via server.registerTool() inside registerInteractionTools(). The registration includes the schema (lines 10-31) and the async handler (lines 34-48).
export function registerInteractionTools(server: McpServer) { server.registerTool( "pinchtab_click", { description: "Click an element by its ref ID (e.g. 'e5'). Uses human-like click by default. Set waitMs to get a snapshot after clicking (saves a round-trip). For SPAs, clicking may not cause full navigation.", inputSchema: z.object({ humanClick: z .boolean() .optional() .describe( "Use real mouse events (default: true). Set to false for programmatic .click().", ), ref: z.string().describe("Element reference ID (e.g. 'e5')"), waitMs: z .number() .optional() .describe( "Wait this many ms after clicking, then return a compact page snapshot (max 10000).", ), waitNav: z .boolean() .optional() .describe("Wait for navigation after click (useful for link clicks). Default: false."), }), title: "Click", }, async ({ ref, humanClick, waitNav, waitMs }) => { try { const kind = humanClick === false ? "click" : "humanClick"; const body: Record<string, unknown> = { kind, ref }; if (waitNav) body.waitNav = true; await pinch("POST", "/action", body); if (waitMs && waitMs > 0) { const snap = await waitAndSnapshot(waitMs); return toolResult(`Clicked ${ref}\n\n${snap}`); } return toolResult({ clicked: ref }); } catch (error) { return toolError(error); } }, ); - src/tools/interaction.ts:10-31 (schema)Zod input schema for pinchtab_click: accepts ref (string, required), humanClick (boolean, optional, defaults to true), waitMs (number, optional, max 10000), and waitNav (boolean, optional, defaults to false).
{ description: "Click an element by its ref ID (e.g. 'e5'). Uses human-like click by default. Set waitMs to get a snapshot after clicking (saves a round-trip). For SPAs, clicking may not cause full navigation.", inputSchema: z.object({ humanClick: z .boolean() .optional() .describe( "Use real mouse events (default: true). Set to false for programmatic .click().", ), ref: z.string().describe("Element reference ID (e.g. 'e5')"), waitMs: z .number() .optional() .describe( "Wait this many ms after clicking, then return a compact page snapshot (max 10000).", ), waitNav: z .boolean() .optional() .describe("Wait for navigation after click (useful for link clicks). Default: false."), }), - src/tools/interaction.ts:34-48 (handler)Async handler for pinchtab_click. Determines click kind (humanClick or programmatic click), sends a POST /action request via the pinch() client, optionally waits for navigation (waitNav) or takes a snapshot (waitMs), and returns the result.
async ({ ref, humanClick, waitNav, waitMs }) => { try { const kind = humanClick === false ? "click" : "humanClick"; const body: Record<string, unknown> = { kind, ref }; if (waitNav) body.waitNav = true; await pinch("POST", "/action", body); if (waitMs && waitMs > 0) { const snap = await waitAndSnapshot(waitMs); return toolResult(`Clicked ${ref}\n\n${snap}`); } return toolResult({ clicked: ref }); } catch (error) { return toolError(error); } }, - src/pinchtab/client.ts:1-49 (helper)The pinch() helper function is the HTTP client that sends requests to the PinchTab server. The click handler calls pinch('POST', '/action', body) to execute the click on the browser.
import { PINCHTAB_TOKEN, PINCHTAB_URL } from "../config.js"; import { ensurePinchtabRunning, isPinchtabRunning } from "./process.js"; const REQUEST_TIMEOUT_MS = 30_000; export async function pinch( method: string, path: string, body?: Record<string, unknown>, ): Promise<unknown> { if (!(await isPinchtabRunning())) { await ensurePinchtabRunning(); } const headers: Record<string, string> = { "Content-Type": "application/json", }; if (PINCHTAB_TOKEN) { headers["Authorization"] = `Bearer ${PINCHTAB_TOKEN}`; } const url = `${PINCHTAB_URL}${path}`; let res: Response; try { res = await fetch(url, { body: body ? JSON.stringify(body) : undefined, headers, method, signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS), }); } catch (error) { if (error instanceof DOMException && error.name === "TimeoutError") { throw new Error(`PinchTab ${method} ${path} timed out after ${REQUEST_TIMEOUT_MS / 1000}s`); } throw error; } if (!res.ok) { const text = await res.text(); throw new Error(`PinchTab ${method} ${path} → ${res.status}: ${text}`); } const contentType = (res.headers.get("content-type") ?? "").split(";")[0].toLowerCase().trim(); if (contentType === "application/json") { return res.json(); } return res.text(); } - src/tools/shared.ts:1-11 (helper)The waitAndSnapshot() helper is used by the click handler when waitMs is provided: waits the given duration, then fetches a compact snapshot and returns it.
import { pinch } from "../pinchtab/client.js"; const MAX_WAIT_MS = 10_000; /** Wait then return a compact snapshot. Shared by navigation and interaction tools. */ export async function waitAndSnapshot(ms: number): Promise<string> { const clamped = Math.min(ms, MAX_WAIT_MS); await new Promise((resolve) => setTimeout(resolve, clamped)); const snapshot = await pinch("GET", "/snapshot?format=compact"); return typeof snapshot === "string" ? snapshot : JSON.stringify(snapshot, undefined, 2); }