webview_wait_for
Wait for a UI element, text content, or IPC event in a Tauri app webview. Supports CSS, XPath, and text strategies with configurable timeout and window target.
Instructions
[Tauri Apps Only] Wait for elements, text, or IPC events in a Tauri app. When type is "selector", supports CSS (default), XPath, and text strategies via the strategy parameter. Requires active driver_session. Targets the only connected app, or the default app if multiple are connected. Specify appIdentifier (port or bundle ID) to target a specific app. For browser waits, use Chrome DevTools MCP instead.
Input 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. | |
| type | Yes | What to wait for | |
| value | Yes | Selector, text content, or IPC event name to wait for | |
| strategy | No | Selector strategy (applies when type is "selector"): "css" (default), "xpath", or "text". | css |
| timeout | No | Timeout in milliseconds (default: 5000ms) |
Implementation Reference
- packages/mcp-server/src/tools-registry.ts:329-356 (registration)Registration of the 'webview_wait_for' tool in the tools registry, with description, schema reference (WaitForSchema), and handler that delegates to the waitFor function.
{ name: 'webview_wait_for', description: '[Tauri Apps Only] Wait for elements, text, or IPC events in a Tauri app. ' + 'When type is "selector", supports CSS (default), XPath, and text strategies via the strategy parameter. ' + 'Requires active driver_session. ' + MULTI_APP_DESC + ' ' + 'For browser waits, use Chrome DevTools MCP instead.', category: TOOL_CATEGORIES.UI_AUTOMATION, schema: WaitForSchema, annotations: { title: 'Wait for Condition in Tauri', readOnlyHint: true, openWorldHint: false, }, handler: async (args) => { const parsed = WaitForSchema.parse(args); return await waitFor({ type: parsed.type, value: parsed.value, strategy: parsed.strategy, timeout: parsed.timeout, windowId: parsed.windowId, appIdentifier: parsed.appIdentifier, }); }, }, - Zod schema WaitForSchema defining the input validation for webview_wait_for: type (selector/text/ipc-event), value, strategy, timeout, windowId, appIdentifier.
export const WaitForSchema = WindowTargetSchema.extend({ type: z.enum([ 'selector', 'text', 'ipc-event' ]).describe('What to wait for'), value: z.string().describe('Selector, text content, or IPC event name to wait for'), strategy: selectorStrategyField.describe( 'Selector strategy (applies when type is "selector"): "css" (default), "xpath", or "text".' ), timeout: z.number().optional().default(5000).describe('Timeout in milliseconds (default: 5000ms)'), }); - The waitFor function (WaitForOptions interface + implementation) that builds the wait-for script and executes it in the webview via executeInWebview.
export interface WaitForOptions { type: string; value: string; strategy?: string; timeout?: number; windowId?: string; appIdentifier?: string | number; } export async function waitFor(options: WaitForOptions): Promise<string> { const { type, value, strategy, timeout = 5000, windowId, appIdentifier } = options; const script = buildScript(SCRIPTS.waitFor, { type, value, strategy: strategy ?? 'css', timeout }); try { return await executeInWebview(script, windowId, appIdentifier); } catch(error: unknown) { const message = error instanceof Error ? error.message : String(error); throw new Error(`Wait failed: ${message}`); } } - SCRIPTS constant loading the wait-for.js script as the 'waitFor' entry, used by buildScript to create injected code.
export const SCRIPTS = { resolveRef: loadScript('resolve-ref'), interact: loadScript('interact'), swipe: loadScript('swipe'), keyboard: loadScript('keyboard'), waitFor: loadScript('wait-for'), getStyles: loadScript('get-styles'), focus: loadScript('focus'), findElement: loadScript('find-element'), domSnapshot: loadScript('dom-snapshot'), elementPicker: loadScript('element-picker'), } as const; - The actual injected JavaScript IIFE that executes in the webview to poll for selectors, text content, or IPC events until timeout.
/** * Wait for conditions script - waits for selectors, text, or events * * @param {Object} params * @param {string} params.type - What to wait for: 'selector', 'text', 'ipc-event' * @param {string} params.value - Selector/ref ID, text, or event name to wait for * @param {string} params.strategy - Selector strategy (applies when type is 'selector'): 'css', 'xpath', or 'text' * @param {number} params.timeout - Timeout in milliseconds */ (async function(params) { const { type, value, strategy, timeout } = params; const startTime = Date.now(); function resolveElement(selectorOrRef) { if (!selectorOrRef) return null; return window.__MCP__.resolveRef(selectorOrRef, strategy); } return new Promise(function(resolve, reject) { function check() { if (Date.now() - startTime > timeout) { reject(new Error('Timeout waiting for ' + type + ': ' + value)); return; } if (type === 'selector') { var element = resolveElement(value); if (element) { var msg = 'Element found: ' + value; var count = window.__MCP__.countAll(value, strategy); if (count > 1) msg += ' (+' + (count - 1) + ' more match' + (count - 1 === 1 ? '' : 'es') + ')'; resolve(msg); return; } } else if (type === 'text') { var found = document.body.innerText.includes(value); if (found) { resolve('Text found: ' + value); return; } } else if (type === 'ipc-event') { // For IPC events, we'd need to set up a listener // This is a simplified version reject(new Error('IPC event waiting not yet implemented in this context')); return; } setTimeout(check, 100); } check(); }); })