tauri_webview_interact
Perform webview interactions in Tauri applications by clicking, scrolling, swiping, or focusing elements to automate UI testing and debugging.
Instructions
[Tauri Apps Only] Click, scroll, swipe, focus, or perform gestures in a Tauri app webview. Supported actions: click, double-click, long-press, scroll, swipe, focus. Requires active tauri_driver_session. For browser interaction, use Chrome DevTools MCP instead.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| windowId | No | Window label to target (defaults to "main") | |
| appIdentifier | No | App port or bundle ID to target. Defaults to the only connected app or the default app if multiple are connected. | |
| action | Yes | Type of interaction to perform | |
| selector | No | CSS selector for the element to interact with | |
| x | No | X coordinate for direct coordinate interaction | |
| y | No | Y coordinate for direct coordinate interaction | |
| duration | No | Duration in ms for long-press or swipe (default: 500ms for long-press, 300ms for swipe) | |
| scrollX | No | Horizontal scroll amount in pixels (positive = right) | |
| scrollY | No | Vertical scroll amount in pixels (positive = down) | |
| fromX | No | Starting X coordinate for swipe | |
| fromY | No | Starting Y coordinate for swipe | |
| toX | No | Ending X coordinate for swipe | |
| toY | No | Ending Y coordinate for swipe |
Implementation Reference
- Core handler function that orchestrates webview interactions for the tauri_webview_interact tool by building and executing scripts based on the action (click, scroll, etc.), handling special cases for swipe and focus.export async function interact(options: { action: string; selector?: string; x?: number; y?: number; duration?: number; scrollX?: number; scrollY?: number; fromX?: number; fromY?: number; toX?: number; toY?: number; windowId?: string; appIdentifier?: string | number; }): Promise<string> { const { action, selector, x, y, duration, scrollX, scrollY, fromX, fromY, toX, toY, windowId, appIdentifier } = options; // Handle swipe action separately since it has different logic if (action === 'swipe') { return performSwipe({ fromX, fromY, toX, toY, duration, windowId, appIdentifier }); } // Handle focus action if (action === 'focus') { if (!selector) { throw new Error('Focus action requires a selector'); } return focusElement({ selector, windowId, appIdentifier }); } const script = buildScript(SCRIPTS.interact, { action, selector: selector ?? null, x: x ?? null, y: y ?? null, duration: duration ?? 500, scrollX: scrollX ?? 0, scrollY: scrollY ?? 0, }); try { return await executeInWebview(script, windowId, appIdentifier); } catch(error: unknown) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Interaction failed: ${message}`); } }
- Zod schema defining the input parameters and validation for the tauri_webview_interact tool.export const InteractSchema = WindowTargetSchema.extend({ action: z.enum([ 'click', 'double-click', 'long-press', 'scroll', 'swipe', 'focus' ]) .describe('Type of interaction to perform'), selector: z.string().optional().describe('CSS selector for the element to interact with'), x: z.number().optional().describe('X coordinate for direct coordinate interaction'), y: z.number().optional().describe('Y coordinate for direct coordinate interaction'), duration: z.number().optional() .describe('Duration in ms for long-press or swipe (default: 500ms for long-press, 300ms for swipe)'), scrollX: z.number().optional().describe('Horizontal scroll amount in pixels (positive = right)'), scrollY: z.number().optional().describe('Vertical scroll amount in pixels (positive = down)'), fromX: z.number().optional().describe('Starting X coordinate for swipe'), fromY: z.number().optional().describe('Starting Y coordinate for swipe'), toX: z.number().optional().describe('Ending X coordinate for swipe'), toY: z.number().optional().describe('Ending Y coordinate for swipe'), });
- packages/mcp-server/src/tools-registry.ts:299-319 (registration)Registration of the tauri_webview_interact tool in the central tools registry, including metadata, schema reference, and thin wrapper handler that parses args and delegates to the interact function.{ name: 'tauri_webview_interact', description: '[Tauri Apps Only] Click, scroll, swipe, focus, or perform gestures in a Tauri app webview. ' + 'Supported actions: click, double-click, long-press, scroll, swipe, focus. ' + 'Requires active tauri_driver_session. ' + 'For browser interaction, use Chrome DevTools MCP instead.', category: TOOL_CATEGORIES.UI_AUTOMATION, schema: InteractSchema, annotations: { title: 'Interact with Tauri Webview', readOnlyHint: false, destructiveHint: false, openWorldHint: false, }, handler: async (args) => { const parsed = InteractSchema.parse(args); return await interact(parsed); }, },
- JavaScript script injected into the Tauri webview to perform the actual DOM manipulations for click, double-click, long-press, and scroll actions using synthetic MouseEvent dispatching./** * Webview interaction script - handles click, double-click, long-press, and scroll actions * This script is injected into the webview and executed with parameters. * * @param {Object} params * @param {string} params.action - The action to perform * @param {string|null} params.selector - CSS selector for the element * @param {number|null} params.x - X coordinate * @param {number|null} params.y - Y coordinate * @param {number} params.duration - Duration for long-press * @param {number} params.scrollX - Horizontal scroll amount * @param {number} params.scrollY - Vertical scroll amount */ (function(params) { const { action, selector, x, y, duration, scrollX, scrollY } = params; let element = null; let targetX, targetY; // For scroll action, we don't necessarily need a selector or coordinates if (action === 'scroll') { if (selector) { element = document.querySelector(selector); if (!element) { throw new Error(`Element not found: ${selector}`); } } } else { // For other actions, we need either selector or coordinates if (selector) { element = document.querySelector(selector); if (!element) { throw new Error(`Element not found: ${selector}`); } const rect = element.getBoundingClientRect(); targetX = rect.left + rect.width / 2; targetY = rect.top + rect.height / 2; } else if (x !== null && y !== null) { targetX = x; targetY = y; element = document.elementFromPoint(x, y); } else { throw new Error('Either selector or coordinates (x, y) must be provided'); } } // Perform the interaction const eventOptions = { bubbles: true, cancelable: true, view: window, clientX: targetX, clientY: targetY, }; if (action === 'click') { if (element) { element.dispatchEvent(new MouseEvent('mousedown', eventOptions)); element.dispatchEvent(new MouseEvent('mouseup', eventOptions)); element.dispatchEvent(new MouseEvent('click', eventOptions)); } return `Clicked at (${targetX}, ${targetY})`; } if (action === 'double-click') { if (element) { element.dispatchEvent(new MouseEvent('mousedown', eventOptions)); element.dispatchEvent(new MouseEvent('mouseup', eventOptions)); element.dispatchEvent(new MouseEvent('click', eventOptions)); element.dispatchEvent(new MouseEvent('mousedown', eventOptions)); element.dispatchEvent(new MouseEvent('mouseup', eventOptions)); element.dispatchEvent(new MouseEvent('click', eventOptions)); element.dispatchEvent(new MouseEvent('dblclick', eventOptions)); } return `Double-clicked at (${targetX}, ${targetY})`; } if (action === 'long-press') { if (element) { element.dispatchEvent(new MouseEvent('mousedown', eventOptions)); setTimeout(() => { element.dispatchEvent(new MouseEvent('mouseup', eventOptions)); }, duration); } return `Long-pressed at (${targetX}, ${targetY}) for ${duration}ms`; } if (action === 'scroll') { const scrollTarget = element || window; if (scrollX !== 0 || scrollY !== 0) { if (scrollTarget === window) { window.scrollBy(scrollX, scrollY); } else { scrollTarget.scrollLeft += scrollX; scrollTarget.scrollTop += scrollY; } return `Scrolled by (${scrollX}, ${scrollY}) pixels`; } return 'No scroll performed (scrollX and scrollY are both 0)'; } throw new Error(`Unknown action: ${action}`); })