rescan_elements
Rescan UI elements on a page after content changes caused by navigation, DOM updates, or user interaction. Keeps annotations up to date.
Instructions
Force the annotated page to rescan all UI elements. Use this after the page content has changed (e.g. after navigation, DOM updates, or user interaction).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/index.js:122-133 (handler)The tool handler function for 'rescan_elements'. It calls proxy.rescan() to queue a 'scan' command to the browser, waits 500ms, then returns the count of elements found.
async () => { proxy.rescan(); // Wait a moment for the scan to complete await new Promise(r => setTimeout(r, 500)); const count = proxy.getElements().length; return { content: [{ type: 'text', text: `Rescanned page. Found ${count} elements.`, }], }; } - src/index.js:117-134 (registration)Registration of the 'rescan_elements' tool using mcp.tool(). Defines the tool name, description, empty schema (no params), and the handler function.
// Tool 4: Rescan page elements mcp.tool( 'rescan_elements', 'Force the annotated page to rescan all UI elements. Use this after the page content has changed (e.g. after navigation, DOM updates, or user interaction).', {}, async () => { proxy.rescan(); // Wait a moment for the scan to complete await new Promise(r => setTimeout(r, 500)); const count = proxy.getElements().length; return { content: [{ type: 'text', text: `Rescanned page. Found ${count} elements.`, }], }; } ); - src/proxy.js:178-178 (helper)The proxy.rescan() method which pushes a { type: 'scan' } command to the pendingCommands queue. This command is polled by the browser-side annotator script.
rescan: () => { pendingCommands.push({ type: 'scan' }); }, - src/annotator.js:33-34 (helper)The client-side handler for the 'scan' command in the browser. When the browser polls commands and receives a scan type, it calls scanElements() and sendElements() to re-scan the DOM and send results back.
if (cmd.type === 'highlight') highlightByName(cmd.name); if (cmd.type === 'scan') { scanElements(); sendElements(); } - src/annotator.js:44-75 (helper)The scanElements() function on the client side that actually traverses the DOM finding roles, aria-labels, ids, classes, buttons, links, inputs, etc. and building the elements array.
function scanElements() { elements = []; const seen = new Set(); // Semantic elements document.querySelectorAll('[role], [aria-label], nav, header, footer, main, aside, section, article, form').forEach(el => { if (el.closest('[data-ui-annotator]')) return; const name = el.getAttribute('aria-label') || el.getAttribute('role') || el.tagName.toLowerCase(); addElement(el, name, 'semantic', seen); }); // Elements with id or class document.querySelectorAll('[id], [class]').forEach(el => { if (el.closest('[data-ui-annotator]')) return; const rect = el.getBoundingClientRect(); if (rect.width < 20 || rect.height < 10) return; const id = el.id; const cls = el.className && typeof el.className === 'string' ? el.className.split(/\\s+/).filter(c => c && !c.startsWith('__')).slice(0, 3).join('.') : ''; const name = id || cls || null; if (name) addElement(el, name, id ? 'id' : 'class', seen); }); // Interactive elements document.querySelectorAll('button, a[href], input, select, textarea').forEach(el => { if (el.closest('[data-ui-annotator]')) return; const text = (el.textContent || el.getAttribute('placeholder') || el.getAttribute('aria-label') || '').trim().slice(0, 40); if (text) addElement(el, text, el.tagName.toLowerCase(), seen); }); }