inspect
Return a numbered list of interactive elements (buttons, links, inputs) from the accessibility tree. Use the returned id with click() or type() — no coordinates needed.
Instructions
Return a numbered list of interactive elements (buttons, links, inputs) from the accessibility tree. Use the returned id with click() or type() — no coordinates needed.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/index.ts:240-248 (handler)The inspect() handler function — tags all interactive DOM elements with data-helm-id, returns a numbered list of items (id, role, name) along with the current URL and count.
async function inspect() { const p = requirePage(); const items = await tagInteractive(p); return { url: p.url(), count: items.length, items, }; } - src/index.ts:379-385 (schema)The inspect tool registration with name, description, and empty inputSchema (no arguments needed).
{ name: 'inspect', description: 'Return a numbered list of interactive elements (buttons, links, inputs) from the ' + 'accessibility tree. Use the returned id with click() or type() — no coordinates needed.', inputSchema: { type: 'object', properties: {} }, }, - src/index.ts:342-446 (registration)TOOLS array definition where inspect is registered alongside all other tools with name, description, and inputSchema.
const TOOLS = [ { name: 'attach', description: 'Connect to a running Chrome instance (must be launched with --remote-debugging-port). ' + 'Returns the active tab URL and total tab count. Always call this first.', inputSchema: { type: 'object', properties: { port: { type: 'number', description: 'CDP port; default 9222' } }, }, }, { name: 'list_tabs', description: 'List all open tabs across contexts. Use to find a specific tab to focus.', inputSchema: { type: 'object', properties: {} }, }, { name: 'focus_tab', description: 'Switch the active tab by index (from list_tabs) or by URL substring.', inputSchema: { type: 'object', properties: { index: { type: 'number' }, urlContains: { type: 'string' }, }, }, }, { name: 'screenshot', description: 'Capture the active tab. Returns base64 PNG, URL, title, and any detected handoff ' + 'triggers (2FA, captcha, payment prompts). Call this after every action to verify state.', inputSchema: { type: 'object', properties: { fullPage: { type: 'boolean', description: 'Full scrollable page (default false)' } }, }, }, { name: 'inspect', description: 'Return a numbered list of interactive elements (buttons, links, inputs) from the ' + 'accessibility tree. Use the returned id with click() or type() — no coordinates needed.', inputSchema: { type: 'object', 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' }, }, }, }, { name: 'type', description: 'Type into a field by id (from inspect) or CSS selector. Set submit=true to press Enter after.', inputSchema: { type: 'object', properties: { text: { type: 'string' }, id: { type: 'number' }, selector: { type: 'string' }, submit: { type: 'boolean' }, }, required: ['text'], }, }, { name: 'navigate', description: 'Navigate the active tab to a URL.', inputSchema: { type: 'object', properties: { url: { type: 'string' } }, required: ['url'], }, }, { name: 'wait_for', description: 'Wait for visible text or a CSS selector to appear on the page.', inputSchema: { type: 'object', properties: { text: { type: 'string' }, selector: { type: 'string' }, timeoutMs: { type: 'number' }, }, }, }, { name: 'handoff', description: 'Pause and ask the human to complete the next step manually (2FA, payment, sensitive ' + 'config). Returns a paused state — the human resolves it in the browser, then tells Claude to continue.', inputSchema: { type: 'object', properties: { reason: { type: 'string' } }, required: ['reason'], }, }, ]; - src/index.ts:465-465 (registration)Switch-case dispatch that routes the 'inspect' tool name to the inspect() function.
case 'inspect': result = await inspect(); break; - src/index.ts:98-139 (helper)The tagInteractive() helper function used by inspect() — walks the DOM, tags interactive elements with data-helm-id, and returns a flat list of {id, role, name} items.
async function tagInteractive(p: Page): Promise<FlatItem[]> { return await p.evaluate((selector) => { document.querySelectorAll('[data-helm-id]').forEach((el) => el.removeAttribute('data-helm-id')); const out: { id: number; role: string; name: string }[] = []; let id = 0; document.querySelectorAll(selector).forEach((el) => { const html = el as HTMLElement; // Skip invisible elements — they're noise and Claude can't see them. const rect = html.getBoundingClientRect(); const style = getComputedStyle(html); if (rect.width === 0 || rect.height === 0) return; if (style.visibility === 'hidden' || style.display === 'none') return; const tag = html.tagName.toLowerCase(); const explicitRole = html.getAttribute('role'); const role = explicitRole || (tag === 'a' ? 'link' : tag === 'button' ? 'button' : tag === 'input' ? (html.getAttribute('type') || 'textbox') : tag === 'textarea' ? 'textbox' : tag === 'select' ? 'combobox' : tag); const name = ( html.getAttribute('aria-label') || html.innerText || html.getAttribute('placeholder') || html.getAttribute('title') || html.getAttribute('value') || '' ).trim().replace(/\s+/g, ' ').slice(0, 120); // Drop empty-named items unless they're inputs (placeholder may be styled out). if (!name && !['textbox', 'combobox', 'checkbox', 'radio'].includes(role)) return; html.setAttribute('data-helm-id', String(id)); out.push({ id, role, name }); id++; }); return out; }, INTERACTIVE_SELECTOR); }