@wdio/mcp 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/server.js CHANGED
@@ -572,35 +572,20 @@ var elementsScript = (elementType = "interactable") => (function() {
572
572
  const isInViewport = rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
573
573
  const info = {
574
574
  tagName: el.tagName.toLowerCase(),
575
+ type: el.getAttribute("type") || "",
576
+ id: el.id || "",
577
+ className: (typeof el.className === "string" ? el.className : "") || "",
578
+ textContent: el.textContent?.trim() || "",
579
+ value: inputEl.value || "",
580
+ placeholder: inputEl.placeholder || "",
581
+ href: el.getAttribute("href") || "",
582
+ ariaLabel: el.getAttribute("aria-label") || "",
583
+ role: el.getAttribute("role") || "",
584
+ src: el.getAttribute("src") || "",
585
+ alt: el.getAttribute("alt") || "",
575
586
  cssSelector: getCssSelector(el),
576
587
  isInViewport
577
588
  };
578
- const type = el.getAttribute("type");
579
- if (type) info.type = type;
580
- const id = el.id;
581
- if (id) info.id = id;
582
- const className = el.className;
583
- if (className && typeof className === "string") info.className = className;
584
- const textContent = el.textContent?.trim();
585
- if (textContent) info.textContent = textContent;
586
- const value = inputEl.value;
587
- if (value) info.value = value;
588
- const placeholder = inputEl.placeholder;
589
- if (placeholder) info.placeholder = placeholder;
590
- const href = el.getAttribute("href");
591
- if (href) info.href = href;
592
- const ariaLabel = el.getAttribute("aria-label");
593
- if (ariaLabel) info.ariaLabel = ariaLabel;
594
- const role = el.getAttribute("role");
595
- if (role) info.role = role;
596
- const src = el.getAttribute("src");
597
- if (src) info.src = src;
598
- const alt = el.getAttribute("alt");
599
- if (alt) info.alt = alt;
600
- if (elementType === "visual" || elementType === "all") {
601
- const bgImage = window.getComputedStyle(el).backgroundImage;
602
- if (bgImage && bgImage !== "none") info.backgroundImage = bgImage;
603
- }
604
589
  return info;
605
590
  });
606
591
  return elementInfos;
@@ -1246,27 +1231,17 @@ function selectBestLocators(locators) {
1246
1231
  }
1247
1232
  function toMobileElementInfo(element, includeBounds) {
1248
1233
  const selectedLocators = selectBestLocators(element.locators);
1234
+ const accessId = element.accessibilityId || element.contentDesc;
1249
1235
  const info = {
1250
1236
  selector: selectedLocators[0] || "",
1251
1237
  tagName: element.tagName,
1252
- isInViewport: element.isInViewport
1238
+ isInViewport: element.isInViewport,
1239
+ text: element.text || "",
1240
+ resourceId: element.resourceId || "",
1241
+ accessibilityId: accessId || "",
1242
+ isEnabled: element.enabled !== false,
1243
+ alternativeSelectors: selectedLocators.length > 1 ? selectedLocators.slice(1) : []
1253
1244
  };
1254
- if (element.text) {
1255
- info.text = element.text;
1256
- }
1257
- if (element.resourceId) {
1258
- info.resourceId = element.resourceId;
1259
- }
1260
- const accessId = element.accessibilityId || element.contentDesc;
1261
- if (accessId) {
1262
- info.accessibilityId = accessId;
1263
- }
1264
- if (!element.enabled) {
1265
- info.isEnabled = false;
1266
- }
1267
- if (selectedLocators.length > 1) {
1268
- info.alternativeSelectors = selectedLocators.slice(1);
1269
- }
1270
1245
  if (includeBounds) {
1271
1246
  info.bounds = element.bounds;
1272
1247
  }
@@ -1299,18 +1274,6 @@ async function getMobileVisibleElements(browser, platform, options = {}) {
1299
1274
  // src/tools/get-visible-elements.tool.ts
1300
1275
  import { encode } from "@toon-format/toon";
1301
1276
  import { z as z7 } from "zod";
1302
-
1303
- // src/utils/strip-undefined.ts
1304
- function stripUndefined(obj) {
1305
- return Object.fromEntries(
1306
- Object.entries(obj).filter(([_, v]) => v !== void 0 && v !== null && v !== "")
1307
- );
1308
- }
1309
- function stripUndefinedFromArray(arr) {
1310
- return arr.map(stripUndefined);
1311
- }
1312
-
1313
- // src/tools/get-visible-elements.tool.ts
1314
1277
  var getVisibleElementsToolDefinition = {
1315
1278
  name: "get_visible_elements",
1316
1279
  description: 'get a list of visible (in viewport & displayed) interactable elements on the page (buttons, links, inputs). Use elementType="visual" for images/SVGs. Must prefer this to take_screenshot for interactions',
@@ -1347,8 +1310,7 @@ var getVisibleElementsTool = async (args) => {
1347
1310
  const platform = browser.isAndroid ? "android" : "ios";
1348
1311
  elements = await getMobileVisibleElements(browser, platform, { includeContainers, includeBounds });
1349
1312
  } else {
1350
- const raw = await browser.execute(get_interactable_browser_elements_default, elementType);
1351
- elements = stripUndefinedFromArray(raw);
1313
+ elements = await browser.execute(get_interactable_browser_elements_default, elementType);
1352
1314
  }
1353
1315
  if (inViewportOnly) {
1354
1316
  elements = elements.filter((el) => el.isInViewport !== false);
@@ -1366,8 +1328,9 @@ var getVisibleElementsTool = async (args) => {
1366
1328
  hasMore: offset + elements.length < total,
1367
1329
  elements
1368
1330
  };
1331
+ const toon = encode(result).replace(/,""/g, ",").replace(/"",/g, ",");
1369
1332
  return {
1370
- content: [{ type: "text", text: encode(result) }]
1333
+ content: [{ type: "text", text: toon }]
1371
1334
  };
1372
1335
  } catch (e) {
1373
1336
  return {
@@ -1554,32 +1517,36 @@ var getAccessibilityToolDefinition = {
1554
1517
  function flattenAccessibilityTree(node, result = []) {
1555
1518
  if (!node) return result;
1556
1519
  if (node.role !== "WebArea" || node.name) {
1557
- const entry = {};
1558
- if (node.role) entry.role = node.role;
1559
- if (node.name) entry.name = node.name;
1560
- if (node.value !== void 0 && node.value !== "") entry.value = node.value;
1561
- if (node.description) entry.description = node.description;
1562
- if (node.keyshortcuts) entry.keyshortcuts = node.keyshortcuts;
1563
- if (node.roledescription) entry.roledescription = node.roledescription;
1564
- if (node.valuetext) entry.valuetext = node.valuetext;
1565
- if (node.disabled) entry.disabled = node.disabled;
1566
- if (node.expanded !== void 0) entry.expanded = node.expanded;
1567
- if (node.focused) entry.focused = node.focused;
1568
- if (node.modal) entry.modal = node.modal;
1569
- if (node.multiline) entry.multiline = node.multiline;
1570
- if (node.multiselectable) entry.multiselectable = node.multiselectable;
1571
- if (node.readonly) entry.readonly = node.readonly;
1572
- if (node.required) entry.required = node.required;
1573
- if (node.selected) entry.selected = node.selected;
1574
- if (node.checked !== void 0) entry.checked = node.checked;
1575
- if (node.pressed !== void 0) entry.pressed = node.pressed;
1576
- if (node.level !== void 0) entry.level = node.level;
1577
- if (node.valuemin !== void 0) entry.valuemin = node.valuemin;
1578
- if (node.valuemax !== void 0) entry.valuemax = node.valuemax;
1579
- if (node.autocomplete) entry.autocomplete = node.autocomplete;
1580
- if (node.haspopup) entry.haspopup = node.haspopup;
1581
- if (node.invalid) entry.invalid = node.invalid;
1582
- if (node.orientation) entry.orientation = node.orientation;
1520
+ const entry = {
1521
+ // Primary identifiers (most useful)
1522
+ role: node.role || "",
1523
+ name: node.name || "",
1524
+ value: node.value ?? "",
1525
+ description: node.description || "",
1526
+ // Boolean states (empty string = not applicable/false)
1527
+ disabled: node.disabled ? "true" : "",
1528
+ focused: node.focused ? "true" : "",
1529
+ selected: node.selected ? "true" : "",
1530
+ checked: node.checked === true ? "true" : node.checked === false ? "false" : node.checked === "mixed" ? "mixed" : "",
1531
+ expanded: node.expanded === true ? "true" : node.expanded === false ? "false" : "",
1532
+ pressed: node.pressed === true ? "true" : node.pressed === false ? "false" : node.pressed === "mixed" ? "mixed" : "",
1533
+ readonly: node.readonly ? "true" : "",
1534
+ required: node.required ? "true" : "",
1535
+ // Less common properties
1536
+ level: node.level ?? "",
1537
+ valuemin: node.valuemin ?? "",
1538
+ valuemax: node.valuemax ?? "",
1539
+ autocomplete: node.autocomplete || "",
1540
+ haspopup: node.haspopup || "",
1541
+ invalid: node.invalid ? "true" : "",
1542
+ modal: node.modal ? "true" : "",
1543
+ multiline: node.multiline ? "true" : "",
1544
+ multiselectable: node.multiselectable ? "true" : "",
1545
+ orientation: node.orientation || "",
1546
+ keyshortcuts: node.keyshortcuts || "",
1547
+ roledescription: node.roledescription || "",
1548
+ valuetext: node.valuetext || ""
1549
+ };
1583
1550
  result.push(entry);
1584
1551
  }
1585
1552
  if (node.children && Array.isArray(node.children)) {
@@ -1639,8 +1606,9 @@ var getAccessibilityTreeTool = async (args) => {
1639
1606
  hasMore: offset + nodes.length < total,
1640
1607
  nodes
1641
1608
  };
1609
+ const toon = encode2(result).replace(/,""/g, ",").replace(/"",/g, ",");
1642
1610
  return {
1643
- content: [{ type: "text", text: encode2(result) }]
1611
+ content: [{ type: "text", text: toon }]
1644
1612
  };
1645
1613
  } catch (e) {
1646
1614
  return {
@@ -2049,7 +2017,7 @@ var package_default = {
2049
2017
  type: "git",
2050
2018
  url: "git://github.com/webdriverio/mcp.git"
2051
2019
  },
2052
- version: "1.6.1",
2020
+ version: "2.0.0",
2053
2021
  description: "MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)",
2054
2022
  main: "./lib/server.js",
2055
2023
  module: "./lib/server.js",
package/lib/server.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.ts","../src/tools/browser.tool.ts","../src/tools/navigate.tool.ts","../src/tools/click.tool.ts","../src/tools/set-value.tool.ts","../src/tools/app-session.tool.ts","../src/config/appium.config.ts","../src/tools/scroll.tool.ts","../src/scripts/get-interactable-browser-elements.ts","../src/locators/source-parsing.ts","../src/locators/element-filter.ts","../src/locators/locator-generation.ts","../src/locators/generate-all-locators.ts","../src/scripts/get-visible-mobile-elements.ts","../src/tools/get-visible-elements.tool.ts","../src/utils/strip-undefined.ts","../src/tools/take-screenshot.tool.ts","../src/tools/cookies.tool.ts","../src/tools/get-accessibility-tree.tool.ts","../src/tools/gestures.tool.ts","../src/tools/app-actions.tool.ts","../src/tools/context.tool.ts","../src/tools/device.tool.ts","../src/tools/execute-script.tool.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { ToolDefinition } from './types/tool';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport {\n closeSessionTool,\n closeSessionToolDefinition,\n startBrowserTool,\n startBrowserToolDefinition\n} from './tools/browser.tool';\nimport { navigateTool, navigateToolDefinition } from './tools/navigate.tool';\nimport { clickTool, clickToolDefinition } from './tools/click.tool';\nimport { setValueTool, setValueToolDefinition } from './tools/set-value.tool';\nimport { scrollTool, scrollToolDefinition } from './tools/scroll.tool';\nimport { getVisibleElementsTool, getVisibleElementsToolDefinition } from './tools/get-visible-elements.tool';\nimport { takeScreenshotTool, takeScreenshotToolDefinition } from './tools/take-screenshot.tool';\nimport {\n deleteCookiesTool,\n deleteCookiesToolDefinition,\n getCookiesTool,\n getCookiesToolDefinition,\n setCookieTool,\n setCookieToolDefinition,\n} from './tools/cookies.tool';\nimport { getAccessibilityToolDefinition, getAccessibilityTreeTool } from './tools/get-accessibility-tree.tool';\nimport { startAppTool, startAppToolDefinition } from './tools/app-session.tool';\nimport {\n dragAndDropTool,\n dragAndDropToolDefinition,\n swipeTool,\n swipeToolDefinition,\n tapElementTool,\n tapElementToolDefinition,\n} from './tools/gestures.tool';\nimport {\n getAppStateTool,\n getAppStateToolDefinition,\n} from './tools/app-actions.tool';\nimport {\n getContextsTool,\n getContextsToolDefinition,\n getCurrentContextTool,\n getCurrentContextToolDefinition,\n switchContextTool,\n switchContextToolDefinition\n} from './tools/context.tool';\nimport {\n getGeolocationTool,\n getGeolocationToolDefinition,\n hideKeyboardTool,\n hideKeyboardToolDefinition,\n rotateDeviceTool,\n rotateDeviceToolDefinition,\n setGeolocationTool,\n setGeolocationToolDefinition,\n} from './tools/device.tool';\nimport { executeScriptTool, executeScriptToolDefinition } from './tools/execute-script.tool';\nimport pkg from '../package.json' with { type: 'json' };\n\n// IMPORTANT: Redirect all console output to stderr to avoid messing with MCP protocol (Chrome writes to console)\nconst _originalConsoleLog = console.log;\nconst _originalConsoleInfo = console.info;\nconst _originalConsoleWarn = console.warn;\nconst _originalConsoleDebug = console.debug;\n\nconsole.log = (...args) => console.error('[LOG]', ...args);\nconsole.info = (...args) => console.error('[INFO]', ...args);\nconsole.warn = (...args) => console.error('[WARN]', ...args);\nconsole.debug = (...args) => console.error('[DEBUG]', ...args);\n\nconst server = new McpServer({\n title: 'WebdriverIO MCP Server',\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n websiteUrl: 'https://github.com/webdriverio/mcp',\n}, {\n instructions: 'MCP server for browser and mobile app automation using WebDriverIO. Supports Chrome browser control (headed/headless) and iOS/Android native app testing via Appium.',\n capabilities: {\n tools: {},\n },\n});\n\n// Helper function to register tools using the new registerTool pattern\nconst registerTool = (definition: ToolDefinition, callback: ToolCallback) =>\n server.registerTool(definition.name, {\n description: definition.description,\n inputSchema: definition.inputSchema,\n }, callback);\n\n// Browser and App Session Management\nregisterTool(startBrowserToolDefinition, startBrowserTool);\nregisterTool(startAppToolDefinition, startAppTool);\nregisterTool(closeSessionToolDefinition, closeSessionTool);\nregisterTool(navigateToolDefinition, navigateTool);\n\n// Element Discovery\nregisterTool(getVisibleElementsToolDefinition, getVisibleElementsTool);\nregisterTool(getAccessibilityToolDefinition, getAccessibilityTreeTool);\n\n// Scrolling\nregisterTool(scrollToolDefinition, scrollTool);\n\n// Element Interaction\nregisterTool(clickToolDefinition, clickTool);\nregisterTool(setValueToolDefinition, setValueTool);\n\n// Screenshots\nregisterTool(takeScreenshotToolDefinition, takeScreenshotTool);\n\n// Cookies\nregisterTool(getCookiesToolDefinition, getCookiesTool);\nregisterTool(setCookieToolDefinition, setCookieTool);\nregisterTool(deleteCookiesToolDefinition, deleteCookiesTool);\n\n// Mobile Gesture Tools\nregisterTool(tapElementToolDefinition, tapElementTool);\nregisterTool(swipeToolDefinition, swipeTool);\nregisterTool(dragAndDropToolDefinition, dragAndDropTool);\n\n// App Lifecycle Management\nregisterTool(getAppStateToolDefinition, getAppStateTool);\n\n// Context Switching (Native/WebView)\nregisterTool(getContextsToolDefinition, getContextsTool);\nregisterTool(getCurrentContextToolDefinition, getCurrentContextTool);\nregisterTool(switchContextToolDefinition, switchContextTool);\n\n// Device Interaction\nregisterTool(rotateDeviceToolDefinition, rotateDeviceTool);\nregisterTool(hideKeyboardToolDefinition, hideKeyboardTool);\nregisterTool(getGeolocationToolDefinition, getGeolocationTool);\nregisterTool(setGeolocationToolDefinition, setGeolocationTool);\n\n// Script Execution (Browser JS / Appium Mobile Commands)\nregisterTool(executeScriptToolDefinition, executeScriptTool);\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error('WebdriverIO MCP Server running on stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error in main():', error);\n process.exit(1);\n});\n","import { remote } from 'webdriverio';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\n\nexport const startBrowserToolDefinition: ToolDefinition = {\n name: 'start_browser',\n description: 'starts a browser session and sets it to the current state',\n inputSchema: {\n headless: z.boolean().optional(),\n windowWidth: z.number().min(400).max(3840).optional().default(1920),\n windowHeight: z.number().min(400).max(2160).optional().default(1080),\n navigationUrl: z.string().optional().describe('URL to navigate to after starting the browser'),\n },\n};\n\nexport const closeSessionToolDefinition: ToolDefinition = {\n name: 'close_session',\n description: 'closes or detaches from the current browser or app session',\n inputSchema: {\n detach: z.boolean().optional().describe('If true, disconnect from session without terminating it (preserves app state). Default: false'),\n },\n};\n\nconst state: {\n browsers: Map<string, WebdriverIO.Browser>;\n currentSession: string | null;\n sessionMetadata: Map<string, { type: 'browser' | 'ios' | 'android'; capabilities: any; isAttached: boolean }>;\n} = {\n browsers: new Map<string, WebdriverIO.Browser>(),\n currentSession: null,\n sessionMetadata: new Map(),\n};\n\nexport const getBrowser = () => {\n const browser = state.browsers.get(state.currentSession);\n if (!browser) {\n throw new Error('No active browser session');\n }\n return browser;\n};\n// Export state for app-session.tool.ts to access\n(getBrowser as any).__state = state;\n\nexport const startBrowserTool: ToolCallback = async ({\n headless = false,\n windowWidth = 1920,\n windowHeight = 1080,\n navigationUrl\n}: {\n headless?: boolean;\n windowWidth?: number;\n windowHeight?: number;\n navigationUrl?: string;\n}): Promise<CallToolResult> => {\n const chromeArgs = [\n `--window-size=${windowWidth},${windowHeight}`,\n '--no-sandbox',\n '--disable-search-engine-choice-screen',\n '--disable-infobars',\n '--log-level=3',\n '--use-fake-device-for-media-stream',\n '--use-fake-ui-for-media-stream',\n '--disable-web-security',\n '--allow-running-insecure-content',\n ];\n\n // Add headless argument if enabled\n if (headless) {\n chromeArgs.push('--headless=new');\n chromeArgs.push('--disable-gpu');\n chromeArgs.push('--disable-dev-shm-usage');\n }\n\n const browser = await remote({\n capabilities: {\n browserName: 'chrome',\n 'goog:chromeOptions': {\n args: chromeArgs,\n },\n acceptInsecureCerts: true,\n },\n });\n\n const { sessionId } = browser;\n state.browsers.set(sessionId, browser);\n state.currentSession = sessionId;\n state.sessionMetadata.set(sessionId, {\n type: 'browser',\n capabilities: browser.capabilities,\n isAttached: false,\n });\n\n // Navigate to URL if provided\n if (navigationUrl) {\n await browser.url(navigationUrl);\n }\n\n const modeText = headless ? 'headless' : 'headed';\n const urlText = navigationUrl ? ` and navigated to ${navigationUrl}` : '';\n return {\n content: [{\n type: 'text',\n text: `Browser started in ${modeText} mode with sessionId: ${sessionId} (${windowWidth}x${windowHeight})${urlText}`,\n }],\n };\n};\n\nexport const closeSessionTool: ToolCallback = async (args: { detach?: boolean } = {}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const sessionId = state.currentSession;\n const metadata = state.sessionMetadata.get(sessionId);\n\n // Only delete session if not detaching\n if (!args.detach) {\n await browser.deleteSession();\n }\n\n // Always clean up local state\n state.browsers.delete(sessionId);\n state.sessionMetadata.delete(sessionId);\n state.currentSession = null;\n\n const action = args.detach ? 'detached from' : 'closed';\n const note = args.detach && !metadata?.isAttached\n ? '\\nNote: Session will remain active on Appium server.'\n : '';\n\n return {\n content: [{ type: 'text', text: `Session ${sessionId} ${action}${note}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error closing session: ${e}` }],\n };\n }\n};","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\n\nexport const navigateToolDefinition: ToolDefinition = {\n name: 'navigate',\n description: 'navigates to a URL',\n inputSchema: {\n url: z.string().min(1).describe('The URL to navigate to'),\n },\n};\n\nexport const navigateTool: ToolCallback = async ({ url}: { url: string }) => {\n try {\n const browser = getBrowser();\n await browser.url(url);\n return {\n content: [{ type: 'text', text: `Navigated to ${url}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error navigating: ${e}` }],\n };\n }\n};\n","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\n\nconst defaultTimeout: number = 3000;\n\nexport const clickToolDefinition: ToolDefinition = {\n name: 'click_element',\n description: 'clicks an element',\n inputSchema: {\n selector: z.string().describe('Value for the selector, in the form of css selector or xpath (\"button.my-class\" or \"//button[@class=\\'my-class\\']\" or \"button=Exact text with spaces\" or \"a*=Link containing text\")'),\n scrollToView: z.boolean().optional().describe('Whether to scroll the element into view before clicking').default(true),\n timeout: z.number().optional().describe('Maximum time to wait for element in milliseconds'),\n },\n};\n\nconst clickAction = async (selector: string, timeout: number, scrollToView = true): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n await browser.waitUntil(browser.$(selector).isExisting, { timeout });\n if (scrollToView) {\n await browser.$(selector).scrollIntoView({ block: 'center', inline: 'center' });\n }\n await browser.$(selector).click();\n return {\n content: [{ type: 'text', text: `Element clicked (selector: ${selector})` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error clicking element: ${e}` }],\n };\n }\n};\n\nexport const clickTool: ToolCallback = async ({ selector, scrollToView, timeout = defaultTimeout}: {\n selector: string;\n scrollToView?: boolean;\n timeout?: number\n}): Promise<CallToolResult> => clickAction(selector, timeout, scrollToView);\n","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\n\nconst defaultTimeout: number = 3000;\n\nexport const setValueToolDefinition: ToolDefinition = {\n name: 'set_value',\n description: 'set value to an element, aka typing',\n inputSchema: {\n selector: z.string().describe('Value for the selector, in the form of css selector or xpath (\"button.my-class\" or \"//button[@class=\\'my-class\\']\")'),\n value: z.string().describe('Text to enter into the element'),\n scrollToView: z.boolean().optional().describe('Whether to scroll the element into view before typing').default(true),\n timeout: z.number().optional().describe('Maximum time to wait for element in milliseconds'),\n },\n};\n\nexport const setValueTool: ToolCallback = async ({ selector, value, scrollToView = true, timeout = defaultTimeout}: {\n selector: string;\n value: string;\n scrollToView?: boolean;\n timeout?: number\n}) => {\n try {\n const browser = getBrowser();\n await browser.waitUntil(browser.$(selector).isExisting, { timeout });\n if (scrollToView) {\n await browser.$(selector).scrollIntoView({ block: 'center', inline: 'center' });\n }\n await browser.$(selector).clearValue();\n await browser.$(selector).setValue(value);\n return {\n content: [{ type: 'text', text: `Text \"${value}\" entered into element` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error entering text: ${e}` }],\n };\n }\n};","import { remote } from 'webdriverio';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { buildAndroidCapabilities, buildIOSCapabilities, getAppiumServerConfig, } from '../config/appium.config';\nimport { getBrowser } from './browser.tool';\n\nexport const startAppToolDefinition: ToolDefinition = {\n name: 'start_app_session',\n description: 'starts a mobile app session (iOS/Android) via Appium',\n inputSchema: {\n platform: z.enum(['iOS', 'Android']).describe('Mobile platform'),\n appPath: z.string().optional().describe('Path to the app file (.app/.apk/.ipa). Required unless noReset=true (connecting to already-running app)'),\n deviceName: z.string().describe('Device/emulator/simulator name'),\n platformVersion: z.string().optional().describe('OS version (e.g., \"17.0\", \"14\")'),\n automationName: z\n .enum(['XCUITest', 'UiAutomator2', 'Espresso'])\n .optional()\n .describe('Automation driver name'),\n appiumHost: z.string().optional().describe('Appium server hostname (overrides APPIUM_URL env var)'),\n appiumPort: z.number().optional().describe('Appium server port (overrides APPIUM_URL_PORT env var)'),\n appiumPath: z.string().optional().describe('Appium server path (overrides APPIUM_PATH env var)'),\n autoGrantPermissions: z.boolean().optional().describe('Auto-grant app permissions (default: true)'),\n autoAcceptAlerts: z.boolean().optional().describe('Auto-accept alerts (default: true)'),\n autoDismissAlerts: z.boolean().optional().describe('Auto-dismiss alerts (default: false, will override \"autoAcceptAlerts\" to undefined if set)'),\n appWaitActivity: z.string().optional().describe('Activity to wait for on launch (Android only)'),\n udid: z.string().optional().describe('Unique Device Identifier for iOS real device testing (e.g., \"00008030-001234567890002E\")'),\n noReset: z.boolean().optional().describe('Do not reset app state before session (preserves app data). Default: false'),\n fullReset: z.boolean().optional().describe('Uninstall app before/after session. Default: true. Set to false with noReset=true to preserve app state completely'),\n newCommandTimeout: z.number().min(0).optional().describe('How long (in seconds) Appium will wait for a new command before assuming the client has quit and ending the session. Default: 60. Set to 300 for 5 minutes, etc.'),\n },\n};\n\n// Access shared state from browser.tool.ts\nexport const getState = () => {\n const sharedState = (getBrowser as any).__state;\n if (!sharedState) {\n throw new Error('Browser state not initialized');\n }\n return sharedState as {\n browsers: Map<string, WebdriverIO.Browser>;\n currentSession: string | null;\n sessionMetadata: Map<string, { type: 'browser' | 'ios' | 'android'; capabilities: any; isAttached: boolean }>;\n };\n};\n\nexport const startAppTool: ToolCallback = async (args: {\n platform: 'iOS' | 'Android';\n appPath?: string;\n deviceName: string;\n platformVersion?: string;\n automationName?: 'XCUITest' | 'UiAutomator2' | 'Espresso';\n appiumHost?: string;\n appiumPort?: number;\n appiumPath?: string;\n autoGrantPermissions?: boolean;\n autoAcceptAlerts?: boolean;\n autoDismissAlerts?: boolean;\n appWaitActivity?: string;\n udid?: string;\n noReset?: boolean;\n fullReset?: boolean;\n newCommandTimeout?: number;\n}): Promise<CallToolResult> => {\n try {\n const {\n platform,\n appPath,\n deviceName,\n platformVersion,\n automationName,\n appiumHost,\n appiumPort,\n appiumPath,\n autoGrantPermissions = true,\n autoAcceptAlerts,\n autoDismissAlerts,\n appWaitActivity,\n udid,\n noReset,\n fullReset,\n newCommandTimeout,\n } = args;\n\n // Validate: either appPath or noReset=true is required\n if (!appPath && noReset !== true) {\n return {\n content: [{\n type: 'text',\n text: 'Error: Either \"appPath\" must be provided to install an app, or \"noReset: true\" must be set to connect to an already-running app.',\n }],\n };\n }\n\n // Get Appium server configuration\n const serverConfig = getAppiumServerConfig({\n hostname: appiumHost,\n port: appiumPort,\n path: appiumPath,\n });\n\n // Build platform-specific capabilities\n const capabilities: Record<string, any> = platform === 'iOS'\n ? buildIOSCapabilities(appPath, {\n deviceName,\n platformVersion,\n automationName: (automationName as 'XCUITest') || 'XCUITest',\n autoGrantPermissions,\n autoAcceptAlerts,\n autoDismissAlerts,\n udid,\n noReset,\n fullReset,\n newCommandTimeout,\n })\n : buildAndroidCapabilities(appPath, {\n deviceName,\n platformVersion,\n automationName: (automationName as 'UiAutomator2' | 'Espresso') || 'UiAutomator2',\n autoGrantPermissions,\n autoAcceptAlerts,\n autoDismissAlerts,\n appWaitActivity,\n noReset,\n fullReset,\n newCommandTimeout,\n });\n\n // Create Appium session\n const browser = await remote({\n protocol: 'http',\n hostname: serverConfig.hostname,\n port: serverConfig.port,\n path: serverConfig.path,\n capabilities,\n });\n\n const { sessionId } = browser;\n\n // Store session and metadata\n // Auto-set isAttached=true when noReset or no appPath to preserve session on close\n const shouldAutoDetach = noReset === true || !appPath;\n const state = getState();\n state.browsers.set(sessionId, browser);\n state.currentSession = sessionId;\n state.sessionMetadata.set(sessionId, {\n type: platform.toLowerCase() as 'ios' | 'android',\n capabilities,\n isAttached: shouldAutoDetach,\n });\n\n const appInfo = appPath ? `\\nApp: ${appPath}` : '\\nApp: (connected to running app)';\n const detachNote = shouldAutoDetach\n ? '\\n\\n(Auto-detach enabled: session will be preserved on close. Use close_session({ detach: false }) to force terminate.)'\n : '';\n return {\n content: [\n {\n type: 'text',\n text: `${platform} app session started with sessionId: ${sessionId}\\nDevice: ${deviceName}${appInfo}\\nAppium Server: ${serverConfig.hostname}:${serverConfig.port}${serverConfig.path}${detachNote}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error starting app session: ${e}` }],\n };\n }\n};\n\n","/**\n * Appium server configuration and capability builders\n */\n\nexport interface AppiumServerConfig {\n hostname: string;\n port: number;\n path: string;\n}\n\nexport interface IOSCapabilityOptions {\n deviceName: string;\n platformVersion?: string;\n automationName?: 'XCUITest';\n autoGrantPermissions?: boolean;\n autoAcceptAlerts?: boolean;\n autoDismissAlerts?: boolean;\n udid?: string;\n noReset?: boolean;\n fullReset?: boolean;\n newCommandTimeout?: number;\n\n [key: string]: any;\n}\n\nexport interface AndroidCapabilityOptions {\n deviceName: string;\n platformVersion?: string;\n automationName?: 'UiAutomator2' | 'Espresso';\n autoGrantPermissions?: boolean;\n autoAcceptAlerts?: boolean;\n autoDismissAlerts?: boolean;\n appWaitActivity?: string;\n noReset?: boolean;\n fullReset?: boolean;\n newCommandTimeout?: number;\n\n [key: string]: any;\n}\n\n/**\n * Get Appium server configuration from environment variables or defaults\n */\nexport function getAppiumServerConfig(overrides?: Partial<AppiumServerConfig>): AppiumServerConfig {\n return {\n hostname: overrides?.hostname || process.env.APPIUM_URL || '127.0.0.1',\n port: overrides?.port || Number(process.env.APPIUM_URL_PORT) || 4723,\n path: overrides?.path || process.env.APPIUM_PATH || '/',\n };\n}\n\n/**\n * Build iOS capabilities for Appium session\n */\nexport function buildIOSCapabilities(\n appPath: string | undefined,\n options: IOSCapabilityOptions,\n): Record<string, any> {\n const capabilities: Record<string, any> = {\n platformName: 'iOS',\n 'appium:platformVersion': options.platformVersion,\n 'appium:deviceName': options.deviceName,\n 'appium:automationName': options.automationName || 'XCUITest',\n };\n\n // Only set app path if provided (allows connecting to already-running app)\n if (appPath) {\n capabilities['appium:app'] = appPath;\n }\n\n // Set UDID for real device testing (required for physical iOS devices)\n if (options.udid) {\n capabilities['appium:udid'] = options.udid;\n }\n\n // Set reset behavior (for preserving app state)\n if (options.noReset !== undefined) {\n capabilities['appium:noReset'] = options.noReset;\n }\n if (options.fullReset !== undefined) {\n capabilities['appium:fullReset'] = options.fullReset;\n }\n\n // Set session timeout (how long Appium waits for new commands)\n if (options.newCommandTimeout !== undefined) {\n capabilities['appium:newCommandTimeout'] = options.newCommandTimeout;\n }\n\n capabilities['appium:autoGrantPermissions'] = options.autoGrantPermissions ?? true;\n capabilities['appium:autoAcceptAlerts'] = options.autoAcceptAlerts ?? true;\n\n if (options.autoDismissAlerts !== undefined) {\n capabilities['appium:autoDismissAlerts'] = options.autoDismissAlerts;\n capabilities['appium:autoAcceptAlerts'] = undefined;\n }\n\n // Add any additional custom options\n for (const [key, value] of Object.entries(options)) {\n if (\n !['deviceName', 'platformVersion', 'automationName', 'autoAcceptAlerts', 'autoDismissAlerts', 'udid', 'noReset', 'fullReset', 'newCommandTimeout'].includes(\n key,\n )\n ) {\n capabilities[`appium:${key}`] = value;\n }\n }\n\n return capabilities;\n}\n\n/**\n * Build Android capabilities for Appium session\n */\nexport function buildAndroidCapabilities(\n appPath: string | undefined,\n options: AndroidCapabilityOptions,\n): Record<string, any> {\n const capabilities: Record<string, any> = {\n platformName: 'Android',\n 'appium:platformVersion': options.platformVersion,\n 'appium:deviceName': options.deviceName,\n 'appium:automationName': options.automationName || 'UiAutomator2',\n };\n\n // Only set app path if provided (allows connecting to already-running app)\n if (appPath) {\n capabilities['appium:app'] = appPath;\n }\n\n // Set reset behavior (for preserving app state)\n if (options.noReset !== undefined) {\n capabilities['appium:noReset'] = options.noReset;\n }\n if (options.fullReset !== undefined) {\n capabilities['appium:fullReset'] = options.fullReset;\n }\n\n // Set session timeout (how long Appium waits for new commands)\n if (options.newCommandTimeout !== undefined) {\n capabilities['appium:newCommandTimeout'] = options.newCommandTimeout;\n }\n\n // Optional Android-specific settings\n capabilities['appium:autoGrantPermissions'] = options.autoGrantPermissions ?? true;\n capabilities['appium:autoAcceptAlerts'] = options.autoAcceptAlerts ?? true;\n\n if (options.autoDismissAlerts !== undefined) {\n capabilities['appium:autoDismissAlerts'] = options.autoDismissAlerts;\n capabilities['appium:autoAcceptAlerts'] = undefined;\n }\n\n if (options.appWaitActivity) {\n capabilities['appium:appWaitActivity'] = options.appWaitActivity;\n }\n\n // Add any additional custom options\n for (const [key, value] of Object.entries(options)) {\n if (\n !['deviceName', 'platformVersion', 'automationName', 'autoGrantPermissions', 'appWaitActivity', 'noReset', 'fullReset', 'newCommandTimeout'].includes(\n key,\n )\n ) {\n capabilities[`appium:${key}`] = value;\n }\n }\n\n return capabilities;\n}\n","import { getBrowser } from './browser.tool';\nimport { getState } from './app-session.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\n\nexport const scrollToolDefinition: ToolDefinition = {\n name: 'scroll',\n description: 'scrolls the page by specified pixels (browser only). For mobile, use the swipe tool.',\n inputSchema: {\n direction: z.enum(['up', 'down']).describe('Scroll direction'),\n pixels: z.number().optional().default(500).describe('Number of pixels to scroll'),\n },\n};\n\nexport const scrollTool: ToolCallback = async ({ direction, pixels = 500 }: { direction: 'up' | 'down'; pixels?: number }) => {\n try {\n const browser = getBrowser();\n const state = getState();\n const metadata = state.sessionMetadata.get(state.currentSession);\n const sessionType = metadata?.type;\n\n if (sessionType !== 'browser') {\n throw new Error('scroll only works in browser sessions. For mobile, use the swipe tool.');\n }\n\n const scrollAmount = direction === 'down' ? pixels : -pixels;\n await browser.execute((amount) => {\n window.scrollBy(0, amount);\n }, scrollAmount);\n\n return {\n content: [{ type: 'text', text: `Scrolled ${direction} ${pixels} pixels` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error scrolling: ${e}` }],\n };\n }\n};","/**\n * Browser script to get visible elements on the page\n * Supports interactable elements, visual elements, or both\n *\n * @param elementType - Type of elements to return: 'interactable', 'visual', or 'all'\n */\nconst elementsScript = (elementType: 'interactable' | 'visual' | 'all' = 'interactable') => (function () {\n const interactableSelectors = [\n 'a[href]', // Links with href\n 'button', // Buttons\n 'input:not([type=\"hidden\"])', // Input fields (except hidden)\n 'select', // Select dropdowns\n 'textarea', // Text areas\n '[role=\"button\"]', // Elements with button role\n '[role=\"link\"]', // Elements with link role\n '[role=\"checkbox\"]', // Elements with checkbox role\n '[role=\"radio\"]', // Elements with radio role\n '[role=\"tab\"]', // Elements with tab role\n '[role=\"menuitem\"]', // Elements with menuitem role\n '[role=\"combobox\"]', // Elements with combobox role\n '[role=\"option\"]', // Elements with option role\n '[role=\"switch\"]', // Elements with switch role\n '[role=\"slider\"]', // Elements with slider role\n '[role=\"textbox\"]', // Elements with textbox role\n '[role=\"searchbox\"]', // Elements with searchbox role\n '[contenteditable=\"true\"]', // Editable content\n '[tabindex]:not([tabindex=\"-1\"])', // Elements with tabindex\n ];\n\n const visualSelectors = [\n 'img', // Images\n 'picture', // Picture elements\n 'svg', // SVG graphics\n 'video', // Video elements\n 'canvas', // Canvas elements\n '[style*=\"background-image\"]', // Elements with background images\n ];\n\n /**\n * Check if an element is visible\n * @param {HTMLElement} element - The element to check\n * @returns {boolean} - Whether the element is visible\n */\n function isVisible(element: HTMLElement) {\n // Use checkVisibility if available (modern browsers)\n if (typeof element.checkVisibility === 'function') {\n return element.checkVisibility({\n opacityProperty: true,\n visibilityProperty: true,\n contentVisibilityAuto: true,\n });\n }\n\n // Fallback for browsers that don't support checkVisibility\n const style = window.getComputedStyle(element);\n return style.display !== 'none' &&\n style.visibility !== 'hidden' &&\n style.opacity !== '0' &&\n element.offsetWidth > 0 &&\n element.offsetHeight > 0;\n }\n\n /**\n * Get a CSS selector for an element\n * @param {HTMLElement} element - The element to get a selector for\n * @returns {string} - The CSS selector\n */\n function getCssSelector(element: HTMLElement) {\n if (element.id) {\n return `#${CSS.escape(element.id)}`;\n }\n\n // Try to build a selector with classes if available\n if (element.className && typeof element.className === 'string') {\n const classes = element.className.trim().split(/\\s+/).filter(Boolean);\n if (classes.length > 0) {\n // Use up to 2 classes to avoid overly complex selectors\n const classSelector = classes.slice(0, 2).map(c => `.${CSS.escape(c)}`).join('');\n const tagWithClass = `${element.tagName.toLowerCase()}${classSelector}`;\n\n // Check if this selector uniquely identifies the element\n if (document.querySelectorAll(tagWithClass).length === 1) {\n return tagWithClass;\n }\n }\n }\n\n // Build a path-based selector\n let current: HTMLElement | null = element;\n const path = [];\n\n while (current && current !== document.documentElement) {\n let selector = current.tagName.toLowerCase();\n\n // Add ID if available\n if (current.id) {\n selector = `#${CSS.escape(current.id)}`;\n path.unshift(selector);\n break;\n }\n\n // Add position among siblings\n const parent = current.parentElement;\n if (parent) {\n const siblings = Array.from(parent.children).filter(child =>\n child.tagName === current!.tagName,\n );\n\n if (siblings.length > 1) {\n const index = siblings.indexOf(current) + 1;\n selector += `:nth-child(${index})`;\n }\n }\n\n path.unshift(selector);\n current = current.parentElement;\n\n // Limit path length to avoid overly complex selectors\n if (path.length >= 4) {\n break;\n }\n }\n\n return path.join(' > ');\n }\n\n /**\n * Get all visible elements on the page based on elementType\n * @returns {Record<string, unknown>[]} - Array of element information objects\n */\n function getElements(): Record<string, unknown>[] {\n // Select which selectors to use based on elementType\n const selectors: string[] = [];\n if (elementType === 'interactable' || elementType === 'all') {\n selectors.push(...interactableSelectors);\n }\n if (elementType === 'visual' || elementType === 'all') {\n selectors.push(...visualSelectors);\n }\n\n // Get all potentially matching elements\n const allElements: Element[] = [];\n selectors.forEach(selector => {\n const elements = document.querySelectorAll(selector);\n elements.forEach(element => {\n if (!allElements.includes(element)) {\n allElements.push(element);\n }\n });\n });\n\n // Filter for visible elements and collect information\n const elementInfos = allElements\n .filter(element => isVisible(element as HTMLElement) && !(element as HTMLInputElement).disabled)\n .map(element => {\n const el = element as HTMLElement;\n const inputEl = element as HTMLInputElement;\n\n // Get element information\n const rect = el.getBoundingClientRect();\n const isInViewport = (\n rect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&\n rect.right <= (window.innerWidth || document.documentElement.clientWidth)\n );\n\n // Build object with only defined values (no null clutter in TOON output)\n const info: Record<string, unknown> = {\n tagName: el.tagName.toLowerCase(),\n cssSelector: getCssSelector(el),\n isInViewport: isInViewport,\n };\n\n // Only add properties that have actual values\n const type = el.getAttribute('type');\n if (type) info.type = type;\n\n const id = el.id;\n if (id) info.id = id;\n\n const className = el.className;\n if (className && typeof className === 'string') info.className = className;\n\n const textContent = el.textContent?.trim();\n if (textContent) info.textContent = textContent;\n\n const value = inputEl.value;\n if (value) info.value = value;\n\n const placeholder = inputEl.placeholder;\n if (placeholder) info.placeholder = placeholder;\n\n const href = el.getAttribute('href');\n if (href) info.href = href;\n\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) info.ariaLabel = ariaLabel;\n\n const role = el.getAttribute('role');\n if (role) info.role = role;\n\n // Visual element specific properties\n const src = el.getAttribute('src');\n if (src) info.src = src;\n\n const alt = el.getAttribute('alt');\n if (alt) info.alt = alt;\n\n // Check for background-image (only if it's a visual element type query)\n if (elementType === 'visual' || elementType === 'all') {\n const bgImage = window.getComputedStyle(el).backgroundImage;\n if (bgImage && bgImage !== 'none') info.backgroundImage = bgImage;\n }\n\n return info;\n });\n\n return elementInfos;\n }\n\n return getElements();\n})();\n\nexport default elementsScript;","/**\n * XML page source parsing utilities\n * Converts Appium page source XML to traversable JSON tree\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/source-parsing.ts\n */\n\nimport { DOMParser } from '@xmldom/xmldom';\n\nexport interface ElementAttributes {\n // Android attributes\n 'resource-id'?: string;\n 'content-desc'?: string;\n text?: string;\n class?: string;\n package?: string;\n clickable?: string;\n 'long-clickable'?: string;\n focusable?: string;\n checkable?: string;\n scrollable?: string;\n enabled?: string;\n displayed?: string;\n bounds?: string; // Format: \"[x1,y1][x2,y2]\"\n\n // iOS attributes\n type?: string;\n name?: string;\n label?: string;\n value?: string;\n accessible?: string;\n visible?: string;\n x?: string;\n y?: string;\n width?: string;\n height?: string;\n\n // Generic\n [key: string]: string | undefined;\n}\n\nexport interface JSONElement {\n children: JSONElement[];\n tagName: string;\n attributes: ElementAttributes;\n path: string; // Dot-separated index path for tree traversal\n}\n\n/**\n * Get child nodes that are elements (not text nodes, comments, etc.)\n */\nfunction childNodesOf(node: Node): Node[] {\n const children: Node[] = [];\n if (node.childNodes) {\n for (let i = 0; i < node.childNodes.length; i++) {\n const child = node.childNodes.item(i);\n if (child?.nodeType === 1) {\n // ELEMENT_NODE\n children.push(child);\n }\n }\n }\n return children;\n}\n\n/**\n * Recursively translate DOM node to JSONElement\n */\nfunction translateRecursively(\n domNode: Node,\n parentPath: string = '',\n index: number | null = null,\n): JSONElement {\n const attributes: ElementAttributes = {};\n\n // Extract attributes if this is an element node\n const element = domNode as Element;\n if (element.attributes) {\n for (let attrIdx = 0; attrIdx < element.attributes.length; attrIdx++) {\n const attr = element.attributes.item(attrIdx);\n if (attr) {\n // Replace newlines in attribute values\n attributes[attr.name] = attr.value.replace(/(\\n)/gm, '\\\\n');\n }\n }\n }\n\n // Build path: dot-separated index chain (e.g., \"0.2.1\")\n const path = index === null ? '' : `${parentPath ? parentPath + '.' : ''}${index}`;\n\n return {\n children: childNodesOf(domNode).map((childNode, childIndex) =>\n translateRecursively(childNode, path, childIndex),\n ),\n tagName: domNode.nodeName,\n attributes,\n path,\n };\n}\n\n/**\n * Convert XML page source to JSON tree structure\n * @param sourceXML - The XML string from getPageSource()\n * @returns JSONElement tree or null if parsing fails\n */\nexport function xmlToJSON(sourceXML: string): JSONElement | null {\n try {\n const parser = new DOMParser();\n const sourceDoc = parser.parseFromString(sourceXML, 'text/xml');\n\n // Handle parsing errors\n const parseErrors = sourceDoc.getElementsByTagName('parsererror');\n if (parseErrors.length > 0) {\n console.error('[xmlToJSON] XML parsing error:', parseErrors[0].textContent);\n return null;\n }\n\n // Get the first element child\n const children = childNodesOf(sourceDoc);\n const firstChild =\n children[0] ||\n (sourceDoc.documentElement ? childNodesOf(sourceDoc.documentElement)[0] : null);\n\n return firstChild\n ? translateRecursively(firstChild)\n : { children: [], tagName: '', attributes: {}, path: '' };\n } catch (e) {\n console.error('[xmlToJSON] Failed to parse XML:', e);\n return null;\n }\n}\n\n/**\n * Parse Android bounds string \"[x1,y1][x2,y2]\" to coordinates\n * @param bounds - Bounds string in format \"[x1,y1][x2,y2]\"\n * @returns Object with x, y, width, height\n */\nexport function parseAndroidBounds(bounds: string): {\n x: number;\n y: number;\n width: number;\n height: number;\n} {\n const match = bounds.match(/\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]/);\n if (!match) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n\n const x1 = parseInt(match[1], 10);\n const y1 = parseInt(match[2], 10);\n const x2 = parseInt(match[3], 10);\n const y2 = parseInt(match[4], 10);\n\n return {\n x: x1,\n y: y1,\n width: x2 - x1,\n height: y2 - y1,\n };\n}\n\n/**\n * Parse iOS element bounds from individual x, y, width, height attributes\n * @param attributes - Element attributes\n * @returns Object with x, y, width, height\n */\nexport function parseIOSBounds(attributes: ElementAttributes): {\n x: number;\n y: number;\n width: number;\n height: number;\n} {\n return {\n x: parseInt(attributes.x || '0', 10),\n y: parseInt(attributes.y || '0', 10),\n width: parseInt(attributes.width || '0', 10),\n height: parseInt(attributes.height || '0', 10),\n };\n}\n\n/**\n * Flatten JSON element tree to array (depth-first)\n * @param root - Root JSONElement\n * @returns Array of all elements in tree\n */\nexport function flattenElementTree(root: JSONElement): JSONElement[] {\n const result: JSONElement[] = [];\n\n function traverse(element: JSONElement) {\n result.push(element);\n for (const child of element.children) {\n traverse(child);\n }\n }\n\n traverse(root);\n return result;\n}\n\n/**\n * Count occurrences of an attribute value in the source XML\n * Used to determine if a selector would be unique\n */\nexport function countAttributeOccurrences(\n sourceXML: string,\n attribute: string,\n value: string,\n): number {\n // Escape special regex characters in value\n const escapedValue = value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Match attribute=\"value\" pattern\n const pattern = new RegExp(`${attribute}=[\"']${escapedValue}[\"']`, 'g');\n const matches = sourceXML.match(pattern);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check if an attribute value is unique in the source\n */\nexport function isAttributeUnique(\n sourceXML: string,\n attribute: string,\n value: string,\n): boolean {\n return countAttributeOccurrences(sourceXML, attribute, value) === 1;\n}\n","/**\n * Element filtering logic for mobile platforms\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/element-filter.ts\n */\n\nimport type { JSONElement } from './source-parsing';\n\nexport interface FilterOptions {\n includeTagNames?: string[]; // Only include these tags (whitelist)\n excludeTagNames?: string[]; // Exclude these tags (blacklist)\n requireAttributes?: string[]; // Must have at least one of these attributes\n minAttributeCount?: number; // Minimum number of non-empty attributes\n fetchableOnly?: boolean; // Only interactable elements\n clickableOnly?: boolean; // Only elements with clickable=\"true\"\n visibleOnly?: boolean; // Only visible/displayed elements\n}\n\n/**\n * Android interactive element types\n */\nexport const ANDROID_INTERACTABLE_TAGS = [\n // Input elements\n 'android.widget.EditText',\n 'android.widget.AutoCompleteTextView',\n 'android.widget.MultiAutoCompleteTextView',\n 'android.widget.SearchView',\n\n // Button-like elements\n 'android.widget.Button',\n 'android.widget.ImageButton',\n 'android.widget.ToggleButton',\n 'android.widget.CompoundButton',\n 'android.widget.RadioButton',\n 'android.widget.CheckBox',\n 'android.widget.Switch',\n 'android.widget.FloatingActionButton',\n 'com.google.android.material.button.MaterialButton',\n 'com.google.android.material.floatingactionbutton.FloatingActionButton',\n\n // Text elements (often tappable)\n 'android.widget.TextView',\n 'android.widget.CheckedTextView',\n\n // Image elements (often tappable)\n 'android.widget.ImageView',\n 'android.widget.QuickContactBadge',\n\n // Selection elements\n 'android.widget.Spinner',\n 'android.widget.SeekBar',\n 'android.widget.RatingBar',\n 'android.widget.ProgressBar',\n 'android.widget.DatePicker',\n 'android.widget.TimePicker',\n 'android.widget.NumberPicker',\n\n // List/grid items\n 'android.widget.AdapterView',\n];\n\n/**\n * iOS interactive element types\n */\nexport const IOS_INTERACTABLE_TAGS = [\n // Input elements\n 'XCUIElementTypeTextField',\n 'XCUIElementTypeSecureTextField',\n 'XCUIElementTypeTextView',\n 'XCUIElementTypeSearchField',\n\n // Button-like elements\n 'XCUIElementTypeButton',\n 'XCUIElementTypeLink',\n\n // Text elements (often tappable)\n 'XCUIElementTypeStaticText',\n\n // Image elements\n 'XCUIElementTypeImage',\n 'XCUIElementTypeIcon',\n\n // Selection elements\n 'XCUIElementTypeSwitch',\n 'XCUIElementTypeSlider',\n 'XCUIElementTypeStepper',\n 'XCUIElementTypeSegmentedControl',\n 'XCUIElementTypePicker',\n 'XCUIElementTypePickerWheel',\n 'XCUIElementTypeDatePicker',\n 'XCUIElementTypePageIndicator',\n\n // Table/list items\n 'XCUIElementTypeCell',\n 'XCUIElementTypeMenuItem',\n 'XCUIElementTypeMenuBarItem',\n\n // Toggle elements\n 'XCUIElementTypeCheckBox',\n 'XCUIElementTypeRadioButton',\n 'XCUIElementTypeToggle',\n\n // Other interactive\n 'XCUIElementTypeKey',\n 'XCUIElementTypeKeyboard',\n 'XCUIElementTypeAlert',\n 'XCUIElementTypeSheet',\n];\n\n/**\n * Android layout containers - typically not interactive targets\n */\nexport const ANDROID_LAYOUT_CONTAINERS = [\n // Core ViewGroup classes\n 'android.view.ViewGroup',\n 'android.view.View',\n 'android.widget.FrameLayout',\n 'android.widget.LinearLayout',\n 'android.widget.RelativeLayout',\n 'android.widget.GridLayout',\n 'android.widget.TableLayout',\n 'android.widget.TableRow',\n 'android.widget.AbsoluteLayout',\n\n // AndroidX layout classes\n 'androidx.constraintlayout.widget.ConstraintLayout',\n 'androidx.coordinatorlayout.widget.CoordinatorLayout',\n 'androidx.appcompat.widget.LinearLayoutCompat',\n 'androidx.cardview.widget.CardView',\n 'androidx.appcompat.widget.ContentFrameLayout',\n 'androidx.appcompat.widget.FitWindowsFrameLayout',\n\n // Scrolling containers\n 'android.widget.ScrollView',\n 'android.widget.HorizontalScrollView',\n 'android.widget.NestedScrollView',\n 'androidx.core.widget.NestedScrollView',\n 'androidx.recyclerview.widget.RecyclerView',\n 'android.widget.ListView',\n 'android.widget.GridView',\n 'android.widget.AbsListView',\n\n // App chrome / system elements\n 'android.widget.ActionBarContainer',\n 'android.widget.ActionBarOverlayLayout',\n 'android.view.ViewStub',\n 'androidx.appcompat.widget.ActionBarContainer',\n 'androidx.appcompat.widget.ActionBarContextView',\n 'androidx.appcompat.widget.ActionBarOverlayLayout',\n\n // Decor views\n 'com.android.internal.policy.DecorView',\n 'android.widget.DecorView',\n];\n\n/**\n * iOS layout containers - typically not interactive targets\n */\nexport const IOS_LAYOUT_CONTAINERS = [\n // Generic containers\n 'XCUIElementTypeOther',\n 'XCUIElementTypeGroup',\n 'XCUIElementTypeLayoutItem',\n\n // Scroll containers\n 'XCUIElementTypeScrollView',\n 'XCUIElementTypeTable',\n 'XCUIElementTypeCollectionView',\n 'XCUIElementTypeScrollBar',\n\n // Navigation chrome\n 'XCUIElementTypeNavigationBar',\n 'XCUIElementTypeTabBar',\n 'XCUIElementTypeToolbar',\n 'XCUIElementTypeStatusBar',\n 'XCUIElementTypeMenuBar',\n\n // Windows and views\n 'XCUIElementTypeWindow',\n 'XCUIElementTypeSheet',\n 'XCUIElementTypeDrawer',\n 'XCUIElementTypeDialog',\n 'XCUIElementTypePopover',\n 'XCUIElementTypePopUpButton',\n\n // Outline elements\n 'XCUIElementTypeOutline',\n 'XCUIElementTypeOutlineRow',\n 'XCUIElementTypeBrowser',\n 'XCUIElementTypeSplitGroup',\n 'XCUIElementTypeSplitter',\n\n // Application root\n 'XCUIElementTypeApplication',\n];\n\n/**\n * Check if element tag matches any in the list (handles partial matches)\n */\nfunction matchesTagList(tagName: string, tagList: string[]): boolean {\n // Exact match\n if (tagList.includes(tagName)) {\n return true;\n }\n\n // Partial match for tags with package prefixes\n for (const tag of tagList) {\n if (tagName.endsWith(tag) || tagName.includes(tag)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if element matches tag name filters\n */\nfunction matchesTagFilters(\n element: JSONElement,\n includeTagNames: string[],\n excludeTagNames: string[],\n): boolean {\n // If include list provided, element must match it\n if (includeTagNames.length > 0 && !matchesTagList(element.tagName, includeTagNames)) {\n return false;\n }\n\n // If element matches exclude list, filter it out\n if (matchesTagList(element.tagName, excludeTagNames)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Check if element matches attribute-based filters\n */\nfunction matchesAttributeFilters(\n element: JSONElement,\n requireAttributes: string[],\n minAttributeCount: number,\n): boolean {\n // Check required attributes\n if (requireAttributes.length > 0) {\n const hasRequiredAttr = requireAttributes.some((attr) => element.attributes?.[attr]);\n if (!hasRequiredAttr) return false;\n }\n\n // Check minimum attribute count\n if (element.attributes && minAttributeCount > 0) {\n const attrCount = Object.values(element.attributes).filter(\n (v) => v !== undefined && v !== null && v !== '',\n ).length;\n if (attrCount < minAttributeCount) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if element is interactable based on platform\n */\nexport function isInteractableElement(\n element: JSONElement,\n isNative: boolean,\n automationName: string,\n): boolean {\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n\n const interactableTags = isAndroid ? ANDROID_INTERACTABLE_TAGS : IOS_INTERACTABLE_TAGS;\n\n // Check if tag is interactable\n if (matchesTagList(element.tagName, interactableTags)) {\n return true;\n }\n\n // Check clickable/focusable attributes (Android)\n if (isAndroid) {\n if (\n element.attributes?.clickable === 'true' ||\n element.attributes?.focusable === 'true' ||\n element.attributes?.checkable === 'true' ||\n element.attributes?.['long-clickable'] === 'true'\n ) {\n return true;\n }\n }\n\n // Check accessible attribute (iOS)\n if (!isAndroid) {\n if (element.attributes?.accessible === 'true') {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if element is a layout container\n */\nexport function isLayoutContainer(element: JSONElement, platform: 'android' | 'ios'): boolean {\n const containerList = platform === 'android' ? ANDROID_LAYOUT_CONTAINERS : IOS_LAYOUT_CONTAINERS;\n return matchesTagList(element.tagName, containerList);\n}\n\n/**\n * Check if element has meaningful content (text, accessibility info)\n * Elements with content should be kept even if they're containers\n */\nexport function hasMeaningfulContent(\n element: JSONElement,\n platform: 'android' | 'ios',\n): boolean {\n const attrs = element.attributes;\n\n // Check for text content\n if (attrs.text && attrs.text.trim() !== '' && attrs.text !== 'null') {\n return true;\n }\n\n if (platform === 'android') {\n // Android: content-desc is accessibility info\n if (attrs['content-desc'] && attrs['content-desc'].trim() !== '' && attrs['content-desc'] !== 'null') {\n return true;\n }\n } else {\n // iOS: label or name is accessibility info\n if (attrs.label && attrs.label.trim() !== '' && attrs.label !== 'null') {\n return true;\n }\n if (attrs.name && attrs.name.trim() !== '' && attrs.name !== 'null') {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine if an element should be included based on all filter criteria\n */\nexport function shouldIncludeElement(\n element: JSONElement,\n filters: FilterOptions,\n isNative: boolean,\n automationName: string,\n): boolean {\n const {\n includeTagNames = [],\n excludeTagNames = ['hierarchy'], // Always exclude root hierarchy node\n requireAttributes = [],\n minAttributeCount = 0,\n fetchableOnly = false,\n clickableOnly = false,\n visibleOnly = true,\n } = filters;\n\n // Check tag name filters\n if (!matchesTagFilters(element, includeTagNames, excludeTagNames)) {\n return false;\n }\n\n // Check attribute filters\n if (!matchesAttributeFilters(element, requireAttributes, minAttributeCount)) {\n return false;\n }\n\n // Check clickable filter (Android only)\n if (clickableOnly && element.attributes?.clickable !== 'true') {\n return false;\n }\n\n // Check visible/displayed filter\n if (visibleOnly) {\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n if (isAndroid && element.attributes?.displayed === 'false') {\n return false;\n }\n if (!isAndroid && element.attributes?.visible === 'false') {\n return false;\n }\n }\n\n // Check fetchable/interactable filter\n if (fetchableOnly && !isInteractableElement(element, isNative, automationName)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get default filter options for a platform\n */\nexport function getDefaultFilters(\n platform: 'android' | 'ios',\n includeContainers: boolean = false,\n): FilterOptions {\n const layoutContainers = platform === 'android' ? ANDROID_LAYOUT_CONTAINERS : IOS_LAYOUT_CONTAINERS;\n\n return {\n excludeTagNames: includeContainers ? ['hierarchy'] : ['hierarchy', ...layoutContainers],\n fetchableOnly: !includeContainers,\n visibleOnly: true,\n clickableOnly: false,\n };\n}\n","/**\n * Generate multiple locator strategies for an element\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/locator-generation.ts\n */\n\nimport type { JSONElement } from './source-parsing';\nimport { isAttributeUnique } from './source-parsing';\n\nexport type LocatorStrategy =\n | 'accessibility-id'\n | 'id'\n | 'class-name'\n | 'xpath'\n | 'predicate-string'\n | 'class-chain'\n | 'uiautomator'\n | 'text';\n\n/**\n * Check if a string value is valid for use in a locator\n */\nfunction isValidValue(value: string | undefined): value is string {\n return value !== undefined && value !== null && value !== 'null' && value.trim() !== '';\n}\n\n/**\n * Escape special characters in text for use in selectors\n */\nfunction escapeText(text: string): string {\n return text.replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n');\n}\n\n/**\n * Get simple locators based on single attributes\n * These are preferred because they're most stable and readable\n */\nfunction getSimpleSuggestedLocators(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): [LocatorStrategy, string][] {\n const results: [LocatorStrategy, string][] = [];\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n const attrs = element.attributes;\n\n if (isAndroid) {\n // Android simple locators\n\n // 1. Resource ID (most stable)\n const resourceId = attrs['resource-id'];\n if (isValidValue(resourceId) && isAttributeUnique(sourceXML, 'resource-id', resourceId)) {\n results.push(['id', `android=new UiSelector().resourceId(\"${resourceId}\")`]);\n }\n\n // 2. Content Description (accessibility)\n const contentDesc = attrs['content-desc'];\n if (isValidValue(contentDesc) && isAttributeUnique(sourceXML, 'content-desc', contentDesc)) {\n results.push(['accessibility-id', `~${contentDesc}`]);\n }\n\n // 3. Text (visible text)\n const text = attrs.text;\n if (isValidValue(text) && text.length < 100 && isAttributeUnique(sourceXML, 'text', text)) {\n results.push(['text', `android=new UiSelector().text(\"${escapeText(text)}\")`]);\n }\n } else {\n // iOS simple locators\n\n // 1. Accessibility ID (name attribute)\n const name = attrs.name;\n if (isValidValue(name) && isAttributeUnique(sourceXML, 'name', name)) {\n results.push(['accessibility-id', `~${name}`]);\n }\n\n // 2. Label (visible text, often same as name)\n const label = attrs.label;\n if (isValidValue(label) && label !== name && isAttributeUnique(sourceXML, 'label', label)) {\n results.push(['predicate-string', `-ios predicate string:label == \"${escapeText(label)}\"`]);\n }\n\n // 3. Value\n const value = attrs.value;\n if (isValidValue(value) && isAttributeUnique(sourceXML, 'value', value)) {\n results.push(['predicate-string', `-ios predicate string:value == \"${escapeText(value)}\"`]);\n }\n }\n\n return results;\n}\n\n/**\n * Build Android UiAutomator selector with multiple attributes\n */\nfunction buildUiAutomatorSelector(element: JSONElement): string | null {\n const attrs = element.attributes;\n const parts: string[] = [];\n\n // Build selector with available attributes\n if (isValidValue(attrs['resource-id'])) {\n parts.push(`resourceId(\"${attrs['resource-id']}\")`);\n }\n if (isValidValue(attrs.text) && attrs.text!.length < 100) {\n parts.push(`text(\"${escapeText(attrs.text!)}\")`);\n }\n if (isValidValue(attrs['content-desc'])) {\n parts.push(`description(\"${attrs['content-desc']}\")`);\n }\n if (isValidValue(attrs.class)) {\n parts.push(`className(\"${attrs.class}\")`);\n }\n\n if (parts.length === 0) return null;\n\n return `android=new UiSelector().${parts.join('.')}`;\n}\n\n/**\n * Build iOS predicate string with multiple conditions\n */\nfunction buildPredicateString(element: JSONElement): string | null {\n const attrs = element.attributes;\n const conditions: string[] = [];\n\n if (isValidValue(attrs.name)) {\n conditions.push(`name == \"${escapeText(attrs.name!)}\"`);\n }\n if (isValidValue(attrs.label)) {\n conditions.push(`label == \"${escapeText(attrs.label!)}\"`);\n }\n if (isValidValue(attrs.value)) {\n conditions.push(`value == \"${escapeText(attrs.value!)}\"`);\n }\n if (attrs.visible === 'true') {\n conditions.push('visible == 1');\n }\n if (attrs.enabled === 'true') {\n conditions.push('enabled == 1');\n }\n\n if (conditions.length === 0) return null;\n\n // Use AND for multiple conditions\n return `-ios predicate string:${conditions.join(' AND ')}`;\n}\n\n/**\n * Build iOS class chain selector\n */\nfunction buildClassChain(element: JSONElement): string | null {\n const attrs = element.attributes;\n const tagName = element.tagName;\n\n // Simple class chain with type\n if (!tagName.startsWith('XCUI')) return null;\n\n let selector = `**/${tagName}`;\n\n // Add label predicate if available\n if (isValidValue(attrs.label)) {\n selector += `[\\`label == \"${escapeText(attrs.label!)}\"\\`]`;\n } else if (isValidValue(attrs.name)) {\n selector += `[\\`name == \"${escapeText(attrs.name!)}\"\\`]`;\n }\n\n return `-ios class chain:${selector}`;\n}\n\n/**\n * Build XPath for element with unique identification\n */\nfunction buildXPath(element: JSONElement, sourceXML: string, isAndroid: boolean): string | null {\n const attrs = element.attributes;\n const tagName = element.tagName;\n const conditions: string[] = [];\n\n if (isAndroid) {\n // Android XPath attributes\n if (isValidValue(attrs['resource-id'])) {\n conditions.push(`@resource-id=\"${attrs['resource-id']}\"`);\n }\n if (isValidValue(attrs['content-desc'])) {\n conditions.push(`@content-desc=\"${attrs['content-desc']}\"`);\n }\n if (isValidValue(attrs.text) && attrs.text!.length < 100) {\n conditions.push(`@text=\"${escapeText(attrs.text!)}\"`);\n }\n } else {\n // iOS XPath attributes\n if (isValidValue(attrs.name)) {\n conditions.push(`@name=\"${attrs.name}\"`);\n }\n if (isValidValue(attrs.label)) {\n conditions.push(`@label=\"${attrs.label}\"`);\n }\n if (isValidValue(attrs.value)) {\n conditions.push(`@value=\"${attrs.value}\"`);\n }\n }\n\n // Build XPath\n if (conditions.length === 0) {\n // Fallback: just the tag\n return `//${tagName}`;\n }\n\n // Combine conditions with 'and'\n return `//${tagName}[${conditions.join(' and ')}]`;\n}\n\n/**\n * Get complex locators (combinations, XPath, etc.)\n */\nfunction getComplexSuggestedLocators(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): [LocatorStrategy, string][] {\n const results: [LocatorStrategy, string][] = [];\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n\n if (isAndroid) {\n // Android complex locators\n\n // UiAutomator with multiple attributes\n const uiAutomator = buildUiAutomatorSelector(element);\n if (uiAutomator) {\n results.push(['uiautomator', uiAutomator]);\n }\n\n // XPath\n const xpath = buildXPath(element, sourceXML, true);\n if (xpath) {\n results.push(['xpath', xpath]);\n }\n\n // Class name (least specific)\n if (isValidValue(element.attributes.class)) {\n results.push([\n 'class-name',\n `android=new UiSelector().className(\"${element.attributes.class}\")`,\n ]);\n }\n } else {\n // iOS complex locators\n\n // Predicate string with multiple conditions\n const predicate = buildPredicateString(element);\n if (predicate) {\n results.push(['predicate-string', predicate]);\n }\n\n // Class chain\n const classChain = buildClassChain(element);\n if (classChain) {\n results.push(['class-chain', classChain]);\n }\n\n // XPath\n const xpath = buildXPath(element, sourceXML, false);\n if (xpath) {\n results.push(['xpath', xpath]);\n }\n\n // Class name (least specific)\n const type = element.tagName;\n if (type.startsWith('XCUIElementType')) {\n results.push(['class-name', `-ios class chain:**/${type}`]);\n }\n }\n\n return results;\n}\n\n/**\n * Get all suggested locators for an element\n * Returns array of [strategy, value] tuples ordered by priority\n *\n * Priority order:\n * Android: id > accessibility-id > text > xpath > uiautomator > class-name\n * iOS: accessibility-id > predicate-string > class-chain > xpath > class-name\n */\nexport function getSuggestedLocators(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): [LocatorStrategy, string][] {\n // Get simple (single attribute) locators first\n const simpleLocators = getSimpleSuggestedLocators(element, sourceXML, isNative, automationName);\n\n // Get complex (combination) locators\n const complexLocators = getComplexSuggestedLocators(element, sourceXML, isNative, automationName);\n\n // Combine, removing duplicates (keep first occurrence)\n const seen = new Set<string>();\n const results: [LocatorStrategy, string][] = [];\n\n for (const locator of [...simpleLocators, ...complexLocators]) {\n if (!seen.has(locator[1])) {\n seen.add(locator[1]);\n results.push(locator);\n }\n }\n\n return results;\n}\n\n/**\n * Get the best (first priority) locator for an element\n */\nexport function getBestLocator(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): string | null {\n const locators = getSuggestedLocators(element, sourceXML, isNative, automationName);\n return locators.length > 0 ? locators[0][1] : null;\n}\n\n/**\n * Convert locator array to object format\n */\nexport function locatorsToObject(locators: [LocatorStrategy, string][]): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [strategy, value] of locators) {\n // Use first locator for each strategy\n if (!result[strategy]) {\n result[strategy] = value;\n }\n }\n return result;\n}\n","/**\n * Main orchestrator for generating locators from page source\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/generate-all-locators.ts\n */\n\nimport type { LocatorStrategy } from './locator-generation';\nimport { getSuggestedLocators, locatorsToObject } from './locator-generation';\nimport type { JSONElement } from './source-parsing';\nimport { parseAndroidBounds, parseIOSBounds, xmlToJSON } from './source-parsing';\nimport type { FilterOptions } from './element-filter';\nimport { hasMeaningfulContent, isLayoutContainer, shouldIncludeElement } from './element-filter';\n\nexport interface ElementWithLocators {\n tagName: string;\n locators: Record<string, string>;\n text: string;\n contentDesc: string;\n resourceId: string;\n accessibilityId: string;\n label: string;\n value: string;\n className: string;\n clickable: boolean;\n enabled: boolean;\n displayed: boolean;\n bounds: { x: number; y: number; width: number; height: number };\n isInViewport: boolean;\n}\n\n/**\n * Processing context - carries all shared state through the processing pipeline\n */\ninterface ProcessingContext {\n sourceXML: string;\n platform: 'android' | 'ios';\n automationName: string;\n isNative: boolean;\n viewportSize: { width: number; height: number };\n filters: FilterOptions;\n results: ElementWithLocators[];\n}\n\n/**\n * Options for generating element locators\n */\nexport interface GenerateLocatorsOptions {\n platform: 'android' | 'ios';\n viewportSize?: { width: number; height: number };\n filters?: FilterOptions;\n isNative?: boolean;\n}\n\n/**\n * Parse element bounds based on platform\n */\nfunction parseBounds(\n element: JSONElement,\n platform: 'android' | 'ios',\n): { x: number; y: number; width: number; height: number } {\n return platform === 'android'\n ? parseAndroidBounds(element.attributes.bounds || '')\n : parseIOSBounds(element.attributes);\n}\n\n/**\n * Check if bounds are within viewport\n */\nfunction isWithinViewport(\n bounds: { x: number; y: number; width: number; height: number },\n viewport: { width: number; height: number },\n): boolean {\n return (\n bounds.x >= 0 &&\n bounds.y >= 0 &&\n bounds.width > 0 &&\n bounds.height > 0 &&\n bounds.x + bounds.width <= viewport.width &&\n bounds.y + bounds.height <= viewport.height\n );\n}\n\n/**\n * Transform JSONElement to ElementWithLocators\n */\nfunction transformElement(element: JSONElement, locators: [LocatorStrategy, string][], ctx: ProcessingContext): ElementWithLocators {\n const attrs = element.attributes;\n const bounds = parseBounds(element, ctx.platform);\n\n return {\n tagName: element.tagName,\n locators: locatorsToObject(locators),\n text: attrs.text || attrs.label || '',\n contentDesc: attrs['content-desc'] || '',\n resourceId: attrs['resource-id'] || '',\n accessibilityId: attrs.name || attrs['content-desc'] || '',\n label: attrs.label || '',\n value: attrs.value || '',\n className: attrs.class || element.tagName,\n clickable: attrs.clickable === 'true' || attrs.accessible === 'true' || attrs['long-clickable'] === 'true',\n enabled: attrs.enabled !== 'false',\n displayed: ctx.platform === 'android' ? attrs.displayed !== 'false' : attrs.visible !== 'false',\n bounds,\n isInViewport: isWithinViewport(bounds, ctx.viewportSize),\n };\n}\n\n/**\n * Check if element should be processed (passes filters or has meaningful content)\n */\nfunction shouldProcess(element: JSONElement, ctx: ProcessingContext): boolean {\n if (shouldIncludeElement(element, ctx.filters, ctx.isNative, ctx.automationName)) {\n return true;\n }\n // Keep layout containers that have meaningful content\n return isLayoutContainer(element, ctx.platform) && hasMeaningfulContent(element, ctx.platform);\n}\n\n/**\n * Process a single element and add to results if valid\n */\nfunction processElement(element: JSONElement, ctx: ProcessingContext): void {\n if (!shouldProcess(element, ctx)) return;\n\n try {\n const locators = getSuggestedLocators(element, ctx.sourceXML, ctx.isNative, ctx.automationName);\n if (locators.length === 0) return;\n\n const transformed = transformElement(element, locators, ctx);\n if (Object.keys(transformed.locators).length === 0) return;\n\n ctx.results.push(transformed);\n } catch (error) {\n console.error(`[processElement] Error at path ${element.path}:`, error);\n }\n}\n\n/**\n * Recursively traverse and process element tree\n */\nfunction traverseTree(element: JSONElement | null, ctx: ProcessingContext): void {\n if (!element) return;\n\n processElement(element, ctx);\n\n for (const child of element.children || []) {\n traverseTree(child, ctx);\n }\n}\n\n/**\n * Generate locators for all elements from page source XML\n */\nexport function generateAllElementLocators(\n sourceXML: string,\n options: GenerateLocatorsOptions,\n): ElementWithLocators[] {\n const sourceJSON = xmlToJSON(sourceXML);\n if (!sourceJSON) {\n console.error('[generateAllElementLocators] Failed to parse page source XML');\n return [];\n }\n\n const ctx: ProcessingContext = {\n sourceXML,\n platform: options.platform,\n automationName: options.platform === 'android' ? 'uiautomator2' : 'xcuitest',\n isNative: options.isNative ?? true,\n viewportSize: options.viewportSize ?? { width: 9999, height: 9999 },\n filters: options.filters ?? {},\n results: [],\n };\n\n traverseTree(sourceJSON, ctx);\n return ctx.results;\n}\n","/**\n * Mobile element detection utilities for iOS and Android\n *\n * Uses page source parsing for optimal performance (2 HTTP calls vs 600+ for 50 elements)\n */\n\nimport type { ElementWithLocators, FilterOptions, LocatorStrategy } from '../locators';\nimport { generateAllElementLocators, getDefaultFilters } from '../locators';\n\n/**\n * Element info returned by getMobileVisibleElements\n * Only includes fields that have actual values (no nulls/undefined)\n */\nexport interface MobileElementInfo {\n selector: string;\n tagName: string;\n isInViewport: boolean;\n // Optional fields - only present when they have meaningful values\n text?: string;\n resourceId?: string;\n accessibilityId?: string;\n isEnabled?: boolean;\n alternativeSelectors?: string[];\n bounds?: { x: number; y: number; width: number; height: number };\n}\n\n/**\n * Options for getMobileVisibleElements\n */\nexport interface GetMobileElementsOptions {\n includeContainers?: boolean;\n includeBounds?: boolean;\n filterOptions?: FilterOptions;\n}\n\n/**\n * Locator strategy priority order for selecting best selector\n * Earlier = higher priority\n */\nconst LOCATOR_PRIORITY: LocatorStrategy[] = [\n 'accessibility-id', // Most stable, cross-platform\n 'id', // Android resource-id\n 'text', // Text-based (can be fragile but readable)\n 'predicate-string', // iOS predicate\n 'class-chain', // iOS class chain\n 'uiautomator', // Android UiAutomator compound\n 'xpath', // XPath (last resort, brittle)\n // 'class-name' intentionally excluded - too generic\n];\n\n/**\n * Select best locators from available strategies\n * Returns [primarySelector, ...alternativeSelectors]\n */\nfunction selectBestLocators(locators: Record<string, string>): string[] {\n const selected: string[] = [];\n\n // Find primary selector based on priority\n for (const strategy of LOCATOR_PRIORITY) {\n if (locators[strategy]) {\n selected.push(locators[strategy]);\n break;\n }\n }\n\n // Add one alternative if available (different strategy)\n for (const strategy of LOCATOR_PRIORITY) {\n if (locators[strategy] && !selected.includes(locators[strategy])) {\n selected.push(locators[strategy]);\n break;\n }\n }\n\n return selected;\n}\n\n/**\n * Convert ElementWithLocators to MobileElementInfo\n * Only includes fields with actual values (mirrors browser script behavior)\n */\nfunction toMobileElementInfo(element: ElementWithLocators, includeBounds: boolean): MobileElementInfo {\n const selectedLocators = selectBestLocators(element.locators);\n\n // Start with required fields\n const info: MobileElementInfo = {\n selector: selectedLocators[0] || '',\n tagName: element.tagName,\n isInViewport: element.isInViewport,\n };\n\n // Only add optional fields if they have meaningful values\n if (element.text) {\n info.text = element.text;\n }\n\n if (element.resourceId) {\n info.resourceId = element.resourceId;\n }\n\n // Use contentDesc for accessibilityId on Android, or name on iOS\n const accessId = element.accessibilityId || element.contentDesc;\n if (accessId) {\n info.accessibilityId = accessId;\n }\n\n // Only include isEnabled if it's false (true is the common case)\n if (!element.enabled) {\n info.isEnabled = false;\n }\n\n // Only add alternative selectors if we have more than one\n if (selectedLocators.length > 1) {\n info.alternativeSelectors = selectedLocators.slice(1);\n }\n\n // Only include bounds if explicitly requested\n if (includeBounds) {\n info.bounds = element.bounds;\n }\n\n return info;\n}\n\n/**\n * Get viewport size from browser\n */\nasync function getViewportSize(browser: WebdriverIO.Browser): Promise<{ width: number; height: number }> {\n try {\n const size = await browser.getWindowSize();\n return { width: size.width, height: size.height };\n } catch {\n return { width: 9999, height: 9999 };\n }\n}\n\n/**\n * Get all visible elements from a mobile app\n *\n * Performance: 2 HTTP calls (getWindowSize + getPageSource) vs 12+ per element with legacy approach\n */\nexport async function getMobileVisibleElements(\n browser: WebdriverIO.Browser,\n platform: 'ios' | 'android',\n options: GetMobileElementsOptions = {},\n): Promise<MobileElementInfo[]> {\n const { includeContainers = false, includeBounds = false, filterOptions } = options;\n\n const viewportSize = await getViewportSize(browser);\n const pageSource = await browser.getPageSource();\n\n const filters: FilterOptions = {\n ...getDefaultFilters(platform, includeContainers),\n ...filterOptions,\n };\n\n const elements = generateAllElementLocators(pageSource, {\n platform,\n viewportSize,\n filters,\n });\n\n return elements.map((el) => toMobileElementInfo(el, includeBounds));\n}\n","import { getBrowser } from './browser.tool';\nimport getInteractableElements from '../scripts/get-interactable-browser-elements';\nimport { getMobileVisibleElements } from '../scripts/get-visible-mobile-elements';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\nimport { encode } from '@toon-format/toon';\nimport { z } from 'zod';\nimport { stripUndefinedFromArray } from '../utils/strip-undefined';\n\n/**\n * Tool definition for get_visible_elements\n */\nexport const getVisibleElementsToolDefinition: ToolDefinition = {\n name: 'get_visible_elements',\n description: 'get a list of visible (in viewport & displayed) interactable elements on the page (buttons, links, inputs). Use elementType=\"visual\" for images/SVGs. Must prefer this to take_screenshot for interactions',\n inputSchema: {\n inViewportOnly: z\n .boolean()\n .optional()\n .describe(\n 'Only return elements within the visible viewport. Default: true. Set to false to get ALL elements on the page.',\n ),\n includeContainers: z\n .boolean()\n .optional()\n .describe(\n 'Include layout containers (ViewGroup, FrameLayout, ScrollView, etc). Default: false. Set to true to see all elements including layouts.',\n ),\n includeBounds: z\n .boolean()\n .optional()\n .describe(\n 'Include element bounds/coordinates (x, y, width, height). Default: false. Set to true for coordinate-based interactions or layout debugging.',\n ),\n elementType: z\n .enum(['interactable', 'visual', 'all'])\n .optional()\n .describe(\n 'Type of elements to return: \"interactable\" (default) for buttons/links/inputs, \"visual\" for images/SVGs, \"all\" for both.',\n ),\n limit: z\n .number()\n .optional()\n .describe('Maximum number of elements to return. Default: 0 (unlimited).'),\n offset: z\n .number()\n .optional()\n .describe('Number of elements to skip (for pagination). Default: 0.'),\n },\n};\n\n/**\n * Get visible elements on the current screen\n * Supports both web browsers and mobile apps (iOS/Android)\n */\nexport const getVisibleElementsTool: ToolCallback = async (args: {\n inViewportOnly?: boolean;\n includeContainers?: boolean;\n includeBounds?: boolean;\n elementType?: 'interactable' | 'visual' | 'all';\n limit?: number;\n offset?: number;\n}) => {\n try {\n const browser = getBrowser();\n const {\n inViewportOnly = true,\n includeContainers = false,\n includeBounds = false,\n elementType = 'interactable',\n limit = 0,\n offset = 0,\n } = args || {};\n\n let elements: { isInViewport?: boolean }[];\n\n if (browser.isAndroid || browser.isIOS) {\n const platform = browser.isAndroid ? 'android' : 'ios';\n elements = await getMobileVisibleElements(browser, platform, { includeContainers, includeBounds });\n } else {\n const raw = await browser.execute(getInteractableElements, elementType);\n elements = stripUndefinedFromArray(raw);\n }\n\n if (inViewportOnly) {\n elements = elements.filter((el) => el.isInViewport !== false);\n }\n\n const total = elements.length;\n\n // Apply pagination\n if (offset > 0) {\n elements = elements.slice(offset);\n }\n if (limit > 0) {\n elements = elements.slice(0, limit);\n }\n\n const result = {\n total,\n showing: elements.length,\n hasMore: offset + elements.length < total,\n elements,\n };\n\n return {\n content: [{ type: 'text', text: encode(result) }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting visible elements: ${e}` }],\n };\n }\n};","/**\n * Utility to strip undefined, null, and empty string values from objects\n *\n * Used to clean up element data before encoding to avoid null clutter in TOON output.\n * TOON format is columnar - it creates a unified schema from ALL objects.\n * If ANY object has a field, ALL rows get that column with null for missing values.\n * By stripping undefined/null/empty values BEFORE encoding, we ensure TOON only\n * creates columns for fields that actually have values.\n */\n\n/**\n * Strip undefined, null, and empty string values from an object\n * @param obj - The object to clean\n * @returns A new object with only defined, non-null, non-empty values\n */\nexport function stripUndefined<T extends Record<string, unknown>>(obj: T): Partial<T> {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, v]) => v !== undefined && v !== null && v !== ''),\n ) as Partial<T>;\n}\n\n/**\n * Strip undefined values from an array of objects\n * @param arr - The array of objects to clean\n * @returns A new array with cleaned objects\n */\nexport function stripUndefinedFromArray<T extends Record<string, unknown>>(arr: T[]): Partial<T>[] {\n return arr.map(stripUndefined);\n}","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\nimport sharp from 'sharp';\n\nconst MAX_DIMENSION = 2000;\nconst MAX_FILE_SIZE_BYTES = 1024 * 1024; // 1MB\n\nexport const takeScreenshotToolDefinition: ToolDefinition = {\n name: 'take_screenshot',\n description: 'captures a screenshot of the current page',\n inputSchema: {\n outputPath: z.string().optional().describe('Optional path where to save the screenshot. If not provided, returns base64 data.'),\n },\n};\n\nasync function processScreenshot(screenshotBase64: string): Promise<{ data: Buffer; mimeType: string }> {\n const inputBuffer = Buffer.from(screenshotBase64, 'base64');\n let image = sharp(inputBuffer);\n const metadata = await image.metadata();\n\n // Resize if any dimension exceeds MAX_DIMENSION\n const width = metadata.width ?? 0;\n const height = metadata.height ?? 0;\n\n if (width > MAX_DIMENSION || height > MAX_DIMENSION) {\n const resizeOptions = width > height\n ? { width: MAX_DIMENSION }\n : { height: MAX_DIMENSION };\n image = image.resize(resizeOptions);\n }\n\n // Try PNG with maximum compression first\n let outputBuffer = await image.png({ compressionLevel: 9 }).toBuffer();\n\n // If still over 1MB, convert to JPEG with progressive quality reduction\n if (outputBuffer.length > MAX_FILE_SIZE_BYTES) {\n let quality = 90;\n while (quality >= 10 && outputBuffer.length > MAX_FILE_SIZE_BYTES) {\n outputBuffer = await image.jpeg({ quality, mozjpeg: true }).toBuffer();\n quality -= 10;\n }\n return { data: outputBuffer, mimeType: 'image/jpeg' };\n }\n\n return { data: outputBuffer, mimeType: 'image/png' };\n}\n\nexport const takeScreenshotTool: ToolCallback = async ({ outputPath }: { outputPath?: string }) => {\n try {\n const browser = getBrowser();\n const screenshot = await browser.takeScreenshot();\n const { data, mimeType } = await processScreenshot(screenshot);\n\n if (outputPath) {\n const fs = await import('node:fs');\n await fs.promises.writeFile(outputPath, data);\n const sizeKB = (data.length / 1024).toFixed(1);\n return {\n content: [{ type: 'text', text: `Screenshot saved to ${outputPath} (${sizeKB}KB, ${mimeType})` }],\n };\n }\n\n const sizeKB = (data.length / 1024).toFixed(1);\n return {\n content: [\n { type: 'text', text: `Screenshot captured (${sizeKB}KB, ${mimeType}):` },\n { type: 'image', data: data.toString('base64'), mimeType },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error taking screenshot: ${(e as Error).message}` }],\n };\n }\n};","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { Cookie } from '@wdio/protocols';\nimport type { ToolDefinition } from '../types/tool';\n\n// Tool definitions\nexport const getCookiesToolDefinition: ToolDefinition = {\n name: 'get_cookies',\n description: 'gets all cookies or a specific cookie by name',\n inputSchema: {\n name: z.string().optional().describe('Optional cookie name to retrieve a specific cookie. If not provided, returns all cookies'),\n },\n};\n\nexport const getCookiesTool: ToolCallback = async ({ name}: { name?: string }): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n if (name) {\n // Get specific cookie by name\n const cookie = await browser.getCookies([name]);\n if (cookie.length === 0) {\n return {\n content: [{ type: 'text', text: `Cookie \"${name}\" not found` }],\n };\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(cookie[0], null, 2) }],\n };\n }\n // Get all cookies\n const cookies = await browser.getCookies();\n if (cookies.length === 0) {\n return {\n content: [{ type: 'text', text: 'No cookies found' }],\n };\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(cookies, null, 2) }],\n };\n\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting cookies: ${e}` }],\n };\n }\n};\n\n// Set a cookie\nexport const setCookieToolDefinition: ToolDefinition = {\n name: 'set_cookie',\n description: 'sets a cookie with specified name, value, and optional attributes',\n inputSchema: {\n name: z.string().describe('Cookie name'),\n value: z.string().describe('Cookie value'),\n domain: z.string().optional().describe('Cookie domain (defaults to current domain)'),\n path: z.string().optional().describe('Cookie path (defaults to \"/\")'),\n expiry: z.number().optional().describe('Expiry date as Unix timestamp in seconds'),\n httpOnly: z.boolean().optional().describe('HttpOnly flag'),\n secure: z.boolean().optional().describe('Secure flag'),\n sameSite: z.enum(['strict', 'lax', 'none']).optional().describe('SameSite attribute'),\n },\n};\n\nexport const setCookieTool: ToolCallback = async ({\n name,\n value,\n domain,\n path = '/',\n expiry,\n httpOnly,\n secure,\n sameSite,\n}: Cookie): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const cookie: Cookie = { name, value, path, domain, expiry, httpOnly, secure, sameSite };\n\n await browser.setCookies(cookie);\n\n return {\n content: [{ type: 'text', text: `Cookie \"${name}\" set successfully` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error setting cookie: ${e}` }],\n };\n }\n};\n\n// Delete cookies\nexport const deleteCookiesToolDefinition: ToolDefinition = {\n name: 'delete_cookies',\n description: 'deletes all cookies or a specific cookie by name',\n inputSchema: {\n name: z.string().optional().describe('Optional cookie name to delete a specific cookie. If not provided, deletes all cookies'),\n },\n};\n\nexport const deleteCookiesTool: ToolCallback = async ({ name}: { name?: string }): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n if (name) {\n // Delete specific cookie by name\n await browser.deleteCookies([name]);\n return {\n content: [{ type: 'text', text: `Cookie \"${name}\" deleted successfully` }],\n };\n }\n // Delete all cookies\n await browser.deleteCookies();\n return {\n content: [{ type: 'text', text: 'All cookies deleted successfully' }],\n };\n\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error deleting cookies: ${e}` }],\n };\n }\n};\n","import { getBrowser } from './browser.tool';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { encode } from '@toon-format/toon';\nimport { z } from 'zod';\n\n/**\n * Tool definition for get_accessibility\n */\nexport const getAccessibilityToolDefinition: ToolDefinition = {\n name: 'get_accessibility',\n description: 'gets accessibility tree snapshot with semantic information about page elements (roles, names, states). Browser-only - use when get_visible_elements does not return expected elements.',\n inputSchema: {\n limit: z.number().optional()\n .describe('Maximum number of nodes to return. Default: 100. Use 0 for unlimited.'),\n offset: z.number().optional()\n .describe('Number of nodes to skip (for pagination). Default: 0.'),\n roles: z.array(z.string()).optional()\n .describe('Filter to specific roles (e.g., [\"button\", \"link\", \"textbox\"]). Default: all roles.'),\n namedOnly: z.boolean().optional()\n .describe('Only return nodes with a name/label. Default: true. Filters out anonymous containers.'),\n },\n};\n\n/**\n * Flatten a hierarchical accessibility tree into a flat list\n * Only includes properties that have actual values (no null clutter)\n * @param node - The accessibility node\n * @param result - Accumulator array\n */\nfunction flattenAccessibilityTree(node: any, result: any[] = []): any[] {\n if (!node) return result;\n\n // Add current node (excluding root WebArea unless it has meaningful content)\n if (node.role !== 'WebArea' || node.name) {\n const entry: Record<string, any> = {};\n\n // Only add properties that have actual values\n if (node.role) entry.role = node.role;\n if (node.name) entry.name = node.name;\n if (node.value !== undefined && node.value !== '') entry.value = node.value;\n if (node.description) entry.description = node.description;\n if (node.keyshortcuts) entry.keyshortcuts = node.keyshortcuts;\n if (node.roledescription) entry.roledescription = node.roledescription;\n if (node.valuetext) entry.valuetext = node.valuetext;\n if (node.disabled) entry.disabled = node.disabled;\n if (node.expanded !== undefined) entry.expanded = node.expanded;\n if (node.focused) entry.focused = node.focused;\n if (node.modal) entry.modal = node.modal;\n if (node.multiline) entry.multiline = node.multiline;\n if (node.multiselectable) entry.multiselectable = node.multiselectable;\n if (node.readonly) entry.readonly = node.readonly;\n if (node.required) entry.required = node.required;\n if (node.selected) entry.selected = node.selected;\n if (node.checked !== undefined) entry.checked = node.checked;\n if (node.pressed !== undefined) entry.pressed = node.pressed;\n if (node.level !== undefined) entry.level = node.level;\n if (node.valuemin !== undefined) entry.valuemin = node.valuemin;\n if (node.valuemax !== undefined) entry.valuemax = node.valuemax;\n if (node.autocomplete) entry.autocomplete = node.autocomplete;\n if (node.haspopup) entry.haspopup = node.haspopup;\n if (node.invalid) entry.invalid = node.invalid;\n if (node.orientation) entry.orientation = node.orientation;\n\n result.push(entry);\n }\n\n // Recursively process children\n if (node.children && Array.isArray(node.children)) {\n for (const child of node.children) {\n flattenAccessibilityTree(child, result);\n }\n }\n\n return result;\n}\n\nexport const getAccessibilityTreeTool: ToolCallback = async (args: {\n limit?: number;\n offset?: number;\n roles?: string[];\n namedOnly?: boolean;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n // Check if this is a mobile session - accessibility tree is browser-only\n if (browser.isAndroid || browser.isIOS) {\n return {\n content: [{\n type: 'text',\n text: 'Error: get_accessibility is browser-only. For mobile apps, use get_visible_elements instead.',\n }],\n };\n }\n\n const { limit = 100, offset = 0, roles, namedOnly = true } = args || {};\n\n // Get Puppeteer instance for native accessibility API\n const puppeteer = await browser.getPuppeteer();\n const pages = await puppeteer.pages();\n\n if (pages.length === 0) {\n return {\n content: [{ type: 'text', text: 'No active pages found' }],\n };\n }\n\n const page = pages[0];\n\n // Get accessibility snapshot with interestingOnly filter\n const snapshot = await page.accessibility.snapshot({\n interestingOnly: true, // Filter to only interesting/semantic nodes\n });\n\n if (!snapshot) {\n return {\n content: [{ type: 'text', text: 'No accessibility tree available' }],\n };\n }\n\n // Flatten the hierarchical tree into a flat list\n let nodes = flattenAccessibilityTree(snapshot);\n\n // Filter to named nodes only (removes anonymous containers, StaticText duplicates)\n if (namedOnly) {\n nodes = nodes.filter(n => n.name && n.name.trim() !== '');\n }\n\n // Filter to specific roles if provided\n if (roles && roles.length > 0) {\n const roleSet = new Set(roles.map(r => r.toLowerCase()));\n nodes = nodes.filter(n => n.role && roleSet.has(n.role.toLowerCase()));\n }\n\n const total = nodes.length;\n\n // Apply pagination\n if (offset > 0) {\n nodes = nodes.slice(offset);\n }\n if (limit > 0) {\n nodes = nodes.slice(0, limit);\n }\n\n const result = {\n total,\n showing: nodes.length,\n hasMore: offset + nodes.length < total,\n nodes,\n };\n\n return {\n content: [{ type: 'text', text: encode(result) }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting accessibility tree: ${e}` }],\n };\n }\n};","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Tap Tool\nexport const tapElementToolDefinition: ToolDefinition = {\n name: 'tap_element',\n description: 'taps an element by selector or screen coordinates (mobile)',\n inputSchema: {\n selector: z\n .string()\n .optional()\n .describe('Element selector (CSS, XPath, accessibility ID, or UiAutomator)'),\n x: z.number().optional().describe('X coordinate for screen tap (if no selector provided)'),\n y: z.number().optional().describe('Y coordinate for screen tap (if no selector provided)'),\n },\n};\n\nexport const tapElementTool: ToolCallback = async (args: {\n selector?: string;\n x?: number;\n y?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { selector, x, y } = args;\n\n if (selector) {\n const element = await browser.$(selector);\n await element.tap();\n return {\n content: [{ type: 'text', text: `Tapped element: ${selector}` }],\n };\n } else if (x !== undefined && y !== undefined) {\n await browser.tap({ x, y });\n return {\n content: [{ type: 'text', text: `Tapped at coordinates: (${x}, ${y})` }],\n };\n }\n\n return {\n content: [{ type: 'text', text: 'Error: Must provide either selector or x,y coordinates' }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error tapping: ${e}` }],\n };\n }\n};\n\n// Swipe Tool\nexport const swipeToolDefinition: ToolDefinition = {\n name: 'swipe',\n description: 'performs a swipe gesture in specified direction (mobile)',\n inputSchema: {\n direction: z.enum(['up', 'down', 'left', 'right']).describe('Swipe direction'),\n duration: z\n .number()\n .min(100)\n .max(5000)\n .optional()\n .describe('Swipe duration in milliseconds (default: 500)'),\n percent: z\n .number()\n .min(0)\n .max(1)\n .optional()\n .describe('Percentage of screen to swipe (0-1, default: 0.5 for up/down, 0.95 for left/right)'),\n },\n};\n\n// Map content direction to finger direction (inverted)\n// \"swipe left\" = content moves left = finger moves right\nconst contentToFingerDirection: Record<string, 'up' | 'down' | 'left' | 'right'> = {\n up: 'down',\n down: 'up',\n left: 'right',\n right: 'left',\n};\n\nexport const swipeTool: ToolCallback = async (args: {\n direction: 'up' | 'down' | 'left' | 'right';\n duration?: number;\n percent?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { direction, duration, percent } = args;\n\n // Direction-specific defaults: vertical (up/down) = 0.5, horizontal (left/right) = 0.95\n const isVertical = direction === 'up' || direction === 'down';\n const defaultPercent = isVertical ? 0.5 : 0.95;\n const effectivePercent = percent ?? defaultPercent;\n const effectiveDuration = duration ?? 500;\n\n // Convert content direction to finger direction\n const fingerDirection = contentToFingerDirection[direction];\n await browser.swipe({ direction: fingerDirection, duration: effectiveDuration, percent: effectivePercent });\n\n return {\n content: [{ type: 'text', text: `Swiped ${direction}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error swiping: ${e}` }],\n };\n }\n};\n\n// Drag and Drop Tool\nexport const dragAndDropToolDefinition: ToolDefinition = {\n name: 'drag_and_drop',\n description: 'drags an element to another element or coordinates (mobile)',\n inputSchema: {\n sourceSelector: z.string().describe('Source element selector to drag'),\n targetSelector: z.string().optional().describe('Target element selector to drop onto'),\n x: z.number().optional().describe('Target X offset (if no targetSelector)'),\n y: z.number().optional().describe('Target Y offset (if no targetSelector)'),\n duration: z.number().min(100).max(5000).optional().describe('Drag duration in milliseconds'),\n },\n};\n\nexport const dragAndDropTool: ToolCallback = async (args: {\n sourceSelector: string;\n targetSelector?: string;\n x?: number;\n y?: number;\n duration?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { sourceSelector, targetSelector, x, y, duration } = args;\n\n const sourceElement = await browser.$(sourceSelector);\n\n if (targetSelector) {\n const targetElement = await browser.$(targetSelector);\n await sourceElement.dragAndDrop(targetElement, { duration });\n return {\n content: [{ type: 'text', text: `Dragged ${sourceSelector} to ${targetSelector}` }],\n };\n } else if (x !== undefined && y !== undefined) {\n await sourceElement.dragAndDrop({ x, y }, { duration });\n return {\n content: [{ type: 'text', text: `Dragged ${sourceSelector} by (${x}, ${y})` }],\n };\n }\n\n return {\n content: [{ type: 'text', text: 'Error: Must provide either targetSelector or x,y coordinates' }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error dragging: ${e}` }],\n };\n }\n};","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Get App State Tool\nexport const getAppStateToolDefinition: ToolDefinition = {\n name: 'get_app_state',\n description: 'gets the state of an app (not installed, not running, background, foreground)',\n inputSchema: {\n bundleId: z.string().describe('App bundle ID (e.g., com.example.app)'),\n },\n};\n\nexport const getAppStateTool: ToolCallback = async (args: {\n bundleId: string;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { bundleId } = args;\n\n const appIdentifier = browser.isAndroid\n ? { appId: bundleId }\n : { bundleId: bundleId };\n\n const state: string = await browser.execute('mobile: queryAppState', appIdentifier);\n\n const stateMap: Record<string, string> = {\n 0: 'not installed',\n 1: 'not running',\n 2: 'running in background (suspended)',\n 3: 'running in background',\n 4: 'running in foreground',\n };\n\n return {\n content: [\n {\n type: 'text',\n text: `App state for ${bundleId}: ${stateMap[state] || 'unknown: ' + state}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting app state: ${e}` }],\n };\n }\n};\n\n","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Get Contexts Tool Definition\nexport const getContextsToolDefinition: ToolDefinition = {\n name: 'get_contexts',\n description: 'lists available contexts (NATIVE_APP, WEBVIEW)',\n inputSchema: {},\n};\n\n// Get Current Context Tool Definition\nexport const getCurrentContextToolDefinition: ToolDefinition = {\n name: 'get_current_context',\n description: 'shows the currently active context',\n inputSchema: {},\n};\n\n// Switch Context Tool Definition\nexport const switchContextToolDefinition: ToolDefinition = {\n name: 'switch_context',\n description: 'switches between native and webview contexts',\n inputSchema: {\n context: z\n .string()\n .describe(\n 'Context name to switch to (e.g., \"NATIVE_APP\", \"WEBVIEW_com.example.app\", or use index from get_contexts)',\n ),\n },\n};\n\n// Get Contexts Tool\nexport const getContextsTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const contexts = await browser.getContexts();\n\n return {\n content: [\n {\n type: 'text',\n text: `Available contexts:\\n${contexts.map((ctx, idx) => `${idx + 1}. ${ctx}`).join('\\n')}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting contexts: ${e}` }],\n };\n }\n};\n\n// Get Current Context Tool\nexport const getCurrentContextTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const currentContext = await browser.getContext();\n\n return {\n content: [{ type: 'text', text: `Current context: ${JSON.stringify(currentContext)}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting current context: ${e}` }],\n };\n }\n};\n\nexport const switchContextTool: ToolCallback = async (args: {\n context: string;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { context } = args;\n\n // If context is a number, get the context by index\n let targetContext = context;\n if (/^\\d+$/.test(context)) {\n const contexts = await browser.getContexts();\n const index = parseInt(context, 10) - 1; // Convert to 0-based index\n if (index >= 0 && index < contexts.length) {\n targetContext = contexts[index] as string;\n } else {\n return {\n content: [\n {\n type: 'text',\n text: `Error: Invalid context index ${context}. Available contexts: ${contexts.length}`,\n },\n ],\n };\n }\n }\n\n await browser.switchContext(targetContext);\n\n return {\n content: [{ type: 'text', text: `Switched to context: ${targetContext}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error switching context: ${e}` }],\n };\n }\n};\n","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Tool Definitions for zero-argument tools\nexport const hideKeyboardToolDefinition: ToolDefinition = {\n name: 'hide_keyboard',\n description: 'hides the on-screen keyboard',\n inputSchema: {},\n};\n\nexport const getGeolocationToolDefinition: ToolDefinition = {\n name: 'get_geolocation',\n description: 'gets current device geolocation',\n inputSchema: {},\n};\n\n// Tool Definitions for tools with arguments\nexport const rotateDeviceToolDefinition: ToolDefinition = {\n name: 'rotate_device',\n description: 'rotates device to portrait or landscape orientation',\n inputSchema: {\n orientation: z.enum(['PORTRAIT', 'LANDSCAPE']).describe('Device orientation'),\n },\n};\n\nexport const setGeolocationToolDefinition: ToolDefinition = {\n name: 'set_geolocation',\n description: 'sets device geolocation (latitude, longitude, altitude)',\n inputSchema: {\n latitude: z.number().min(-90).max(90).describe('Latitude coordinate'),\n longitude: z.number().min(-180).max(180).describe('Longitude coordinate'),\n altitude: z.number().optional().describe('Altitude in meters (optional)'),\n },\n};\n\n// Rotate Device Tool\nexport const rotateDeviceTool: ToolCallback = async (args: {\n orientation: 'PORTRAIT' | 'LANDSCAPE';\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { orientation } = args;\n\n await browser.setOrientation(orientation);\n\n return {\n content: [{ type: 'text', text: `Device rotated to: ${orientation}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error rotating device: ${e}` }],\n };\n }\n};\n\n// Hide Keyboard Tool\nexport const hideKeyboardTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n await browser.hideKeyboard();\n\n return {\n content: [{ type: 'text', text: 'Keyboard hidden' }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error hiding keyboard: ${e}` }],\n };\n }\n};\n\n// Get Geolocation Tool\nexport const getGeolocationTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const location = await browser.getGeoLocation();\n\n return {\n content: [\n {\n type: 'text',\n text: `Location:\\n Latitude: ${location.latitude}\\n Longitude: ${location.longitude}\\n Altitude: ${location.altitude || 'N/A'}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting geolocation: ${e}` }],\n };\n }\n};\n\n// Set Geolocation Tool\nexport const setGeolocationTool: ToolCallback = async (args: {\n latitude: number;\n longitude: number;\n altitude?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { latitude, longitude, altitude } = args;\n\n await browser.setGeoLocation({ latitude, longitude, altitude });\n\n return {\n content: [\n {\n type: 'text',\n text: `Geolocation set to:\\n Latitude: ${latitude}\\n Longitude: ${longitude}${altitude ? `\\n Altitude: ${altitude}m` : ''}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error setting geolocation: ${e}` }],\n };\n }\n};\n","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\nexport const executeScriptToolDefinition: ToolDefinition = {\n name: 'execute_script',\n description: `Executes JavaScript in browser or mobile commands via Appium.\n\n**Browser:** Runs JavaScript in page context. Use 'return' to get values back.\n - Example: execute_script({ script: \"return document.title\" })\n - Example: execute_script({ script: \"return window.scrollY\" })\n - Example: execute_script({ script: \"arguments[0].click()\", args: [\"#myButton\"] })\n\n**Mobile (Appium):** Executes mobile-specific commands using 'mobile: <command>' syntax.\n - Press key (Android): execute_script({ script: \"mobile: pressKey\", args: [{ keycode: 4 }] }) // BACK=4, HOME=3\n - Activate app: execute_script({ script: \"mobile: activateApp\", args: [{ appId: \"com.example\" }] })\n - Terminate app: execute_script({ script: \"mobile: terminateApp\", args: [{ appId: \"com.example\" }] })\n - Deep link: execute_script({ script: \"mobile: deepLink\", args: [{ url: \"myapp://screen\", package: \"com.example\" }] })\n - Shell command (Android): execute_script({ script: \"mobile: shell\", args: [{ command: \"dumpsys\", args: [\"battery\"] }] })`,\n inputSchema: {\n script: z.string().describe('JavaScript code (browser) or mobile command string like \"mobile: pressKey\" (Appium)'),\n args: z.array(z.any()).optional().describe('Arguments to pass to the script. For browser: element selectors or values. For mobile commands: command-specific parameters as objects.'),\n },\n};\n\nexport const executeScriptTool: ToolCallback = async (args: {\n script: string;\n args?: unknown[];\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { script, args: scriptArgs = [] } = args;\n\n // For browser scripts with selector arguments, resolve them to elements\n const resolvedArgs = await Promise.all(\n scriptArgs.map(async (arg) => {\n // If it's a string that looks like a selector and we're in browser context, try to resolve it\n if (typeof arg === 'string' && !script.startsWith('mobile:')) {\n try {\n const element = await browser.$(arg);\n if (await element.isExisting()) {\n return element;\n }\n } catch {\n // Not a valid selector, pass as-is\n }\n }\n return arg;\n })\n );\n\n const result = await browser.execute(script, ...resolvedArgs);\n\n // Format result for display\n let resultText: string;\n if (result === undefined || result === null) {\n resultText = 'Script executed successfully (no return value)';\n } else if (typeof result === 'object') {\n try {\n resultText = `Result: ${JSON.stringify(result, null, 2)}`;\n } catch {\n resultText = `Result: ${String(result)}`;\n }\n } else {\n resultText = `Result: ${result}`;\n }\n\n return {\n content: [{ type: 'text', text: resultText }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error executing script: ${e}` }],\n };\n }\n};\n","{\n \"name\": \"@wdio/mcp\",\n \"author\": \"Vince Graics\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git://github.com/webdriverio/mcp.git\"\n },\n \"version\": \"1.6.1\",\n \"description\": \"MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)\",\n \"main\": \"./lib/server.js\",\n \"module\": \"./lib/server.js\",\n \"types\": \"./lib/server.d.ts\",\n \"bin\": {\n \"wdio-mcp\": \"lib/server.js\"\n },\n \"license\": \"MIT\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"type\": \"module\",\n \"files\": [\n \"lib\",\n \"README.md\"\n ],\n \"scripts\": {\n \"prebundle\": \"rimraf lib --glob ./*.tgz\",\n \"bundle\": \"tsup && shx chmod +x lib/server.js\",\n \"postbundle\": \"npm pack\",\n \"lint\": \"eslint src/ --fix && tsc --noEmit\",\n \"start\": \"node lib/server.js\",\n \"dev\": \"tsx --watch src/server.ts\",\n \"prepare\": \"husky\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"1.25\",\n \"@toon-format/toon\": \"^2.1.0\",\n \"@wdio/protocols\": \"^9.16.2\",\n \"@xmldom/xmldom\": \"^0.8.11\",\n \"puppeteer-core\": \"^24.35.0\",\n \"sharp\": \"^0.34.5\",\n \"webdriverio\": \"9.23\",\n \"zod\": \"^4.3.5\"\n },\n \"devDependencies\": {\n \"@release-it/conventional-changelog\": \"^10.0.4\",\n \"@types/node\": \"^20.11.0\",\n \"@wdio/eslint\": \"^0.1.3\",\n \"@wdio/types\": \"^9.20.0\",\n \"eslint\": \"^9.39.2\",\n \"husky\": \"^9.1.7\",\n \"release-it\": \"^19.2.3\",\n \"rimraf\": \"^6.1.2\",\n \"shx\": \"^0.4.0\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"5.9\"\n },\n \"packageManager\": \"pnpm@10.12.4\"\n}\n"],"mappings":"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","names":["z","z","z","defaultTimeout","remote","z","z","remote","state","z","state","z","z","z","sizeKB","z","encode","z","z","z","z","z","state","z","z","z","z","z","z"]}
1
+ {"version":3,"sources":["../src/server.ts","../src/tools/browser.tool.ts","../src/tools/navigate.tool.ts","../src/tools/click.tool.ts","../src/tools/set-value.tool.ts","../src/tools/app-session.tool.ts","../src/config/appium.config.ts","../src/tools/scroll.tool.ts","../src/scripts/get-interactable-browser-elements.ts","../src/locators/source-parsing.ts","../src/locators/element-filter.ts","../src/locators/locator-generation.ts","../src/locators/generate-all-locators.ts","../src/scripts/get-visible-mobile-elements.ts","../src/tools/get-visible-elements.tool.ts","../src/tools/take-screenshot.tool.ts","../src/tools/cookies.tool.ts","../src/tools/get-accessibility-tree.tool.ts","../src/tools/gestures.tool.ts","../src/tools/app-actions.tool.ts","../src/tools/context.tool.ts","../src/tools/device.tool.ts","../src/tools/execute-script.tool.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { ToolDefinition } from './types/tool';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport {\n closeSessionTool,\n closeSessionToolDefinition,\n startBrowserTool,\n startBrowserToolDefinition\n} from './tools/browser.tool';\nimport { navigateTool, navigateToolDefinition } from './tools/navigate.tool';\nimport { clickTool, clickToolDefinition } from './tools/click.tool';\nimport { setValueTool, setValueToolDefinition } from './tools/set-value.tool';\nimport { scrollTool, scrollToolDefinition } from './tools/scroll.tool';\nimport { getVisibleElementsTool, getVisibleElementsToolDefinition } from './tools/get-visible-elements.tool';\nimport { takeScreenshotTool, takeScreenshotToolDefinition } from './tools/take-screenshot.tool';\nimport {\n deleteCookiesTool,\n deleteCookiesToolDefinition,\n getCookiesTool,\n getCookiesToolDefinition,\n setCookieTool,\n setCookieToolDefinition,\n} from './tools/cookies.tool';\nimport { getAccessibilityToolDefinition, getAccessibilityTreeTool } from './tools/get-accessibility-tree.tool';\nimport { startAppTool, startAppToolDefinition } from './tools/app-session.tool';\nimport {\n dragAndDropTool,\n dragAndDropToolDefinition,\n swipeTool,\n swipeToolDefinition,\n tapElementTool,\n tapElementToolDefinition,\n} from './tools/gestures.tool';\nimport {\n getAppStateTool,\n getAppStateToolDefinition,\n} from './tools/app-actions.tool';\nimport {\n getContextsTool,\n getContextsToolDefinition,\n getCurrentContextTool,\n getCurrentContextToolDefinition,\n switchContextTool,\n switchContextToolDefinition\n} from './tools/context.tool';\nimport {\n getGeolocationTool,\n getGeolocationToolDefinition,\n hideKeyboardTool,\n hideKeyboardToolDefinition,\n rotateDeviceTool,\n rotateDeviceToolDefinition,\n setGeolocationTool,\n setGeolocationToolDefinition,\n} from './tools/device.tool';\nimport { executeScriptTool, executeScriptToolDefinition } from './tools/execute-script.tool';\nimport pkg from '../package.json' with { type: 'json' };\n\n// IMPORTANT: Redirect all console output to stderr to avoid messing with MCP protocol (Chrome writes to console)\nconst _originalConsoleLog = console.log;\nconst _originalConsoleInfo = console.info;\nconst _originalConsoleWarn = console.warn;\nconst _originalConsoleDebug = console.debug;\n\nconsole.log = (...args) => console.error('[LOG]', ...args);\nconsole.info = (...args) => console.error('[INFO]', ...args);\nconsole.warn = (...args) => console.error('[WARN]', ...args);\nconsole.debug = (...args) => console.error('[DEBUG]', ...args);\n\nconst server = new McpServer({\n title: 'WebdriverIO MCP Server',\n name: pkg.name,\n version: pkg.version,\n description: pkg.description,\n websiteUrl: 'https://github.com/webdriverio/mcp',\n}, {\n instructions: 'MCP server for browser and mobile app automation using WebDriverIO. Supports Chrome browser control (headed/headless) and iOS/Android native app testing via Appium.',\n capabilities: {\n tools: {},\n },\n});\n\n// Helper function to register tools using the new registerTool pattern\nconst registerTool = (definition: ToolDefinition, callback: ToolCallback) =>\n server.registerTool(definition.name, {\n description: definition.description,\n inputSchema: definition.inputSchema,\n }, callback);\n\n// Browser and App Session Management\nregisterTool(startBrowserToolDefinition, startBrowserTool);\nregisterTool(startAppToolDefinition, startAppTool);\nregisterTool(closeSessionToolDefinition, closeSessionTool);\nregisterTool(navigateToolDefinition, navigateTool);\n\n// Element Discovery\nregisterTool(getVisibleElementsToolDefinition, getVisibleElementsTool);\nregisterTool(getAccessibilityToolDefinition, getAccessibilityTreeTool);\n\n// Scrolling\nregisterTool(scrollToolDefinition, scrollTool);\n\n// Element Interaction\nregisterTool(clickToolDefinition, clickTool);\nregisterTool(setValueToolDefinition, setValueTool);\n\n// Screenshots\nregisterTool(takeScreenshotToolDefinition, takeScreenshotTool);\n\n// Cookies\nregisterTool(getCookiesToolDefinition, getCookiesTool);\nregisterTool(setCookieToolDefinition, setCookieTool);\nregisterTool(deleteCookiesToolDefinition, deleteCookiesTool);\n\n// Mobile Gesture Tools\nregisterTool(tapElementToolDefinition, tapElementTool);\nregisterTool(swipeToolDefinition, swipeTool);\nregisterTool(dragAndDropToolDefinition, dragAndDropTool);\n\n// App Lifecycle Management\nregisterTool(getAppStateToolDefinition, getAppStateTool);\n\n// Context Switching (Native/WebView)\nregisterTool(getContextsToolDefinition, getContextsTool);\nregisterTool(getCurrentContextToolDefinition, getCurrentContextTool);\nregisterTool(switchContextToolDefinition, switchContextTool);\n\n// Device Interaction\nregisterTool(rotateDeviceToolDefinition, rotateDeviceTool);\nregisterTool(hideKeyboardToolDefinition, hideKeyboardTool);\nregisterTool(getGeolocationToolDefinition, getGeolocationTool);\nregisterTool(setGeolocationToolDefinition, setGeolocationTool);\n\n// Script Execution (Browser JS / Appium Mobile Commands)\nregisterTool(executeScriptToolDefinition, executeScriptTool);\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n console.error('WebdriverIO MCP Server running on stdio');\n}\n\nmain().catch((error) => {\n console.error('Fatal error in main():', error);\n process.exit(1);\n});\n","import { remote } from 'webdriverio';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\n\nexport const startBrowserToolDefinition: ToolDefinition = {\n name: 'start_browser',\n description: 'starts a browser session and sets it to the current state',\n inputSchema: {\n headless: z.boolean().optional(),\n windowWidth: z.number().min(400).max(3840).optional().default(1920),\n windowHeight: z.number().min(400).max(2160).optional().default(1080),\n navigationUrl: z.string().optional().describe('URL to navigate to after starting the browser'),\n },\n};\n\nexport const closeSessionToolDefinition: ToolDefinition = {\n name: 'close_session',\n description: 'closes or detaches from the current browser or app session',\n inputSchema: {\n detach: z.boolean().optional().describe('If true, disconnect from session without terminating it (preserves app state). Default: false'),\n },\n};\n\nconst state: {\n browsers: Map<string, WebdriverIO.Browser>;\n currentSession: string | null;\n sessionMetadata: Map<string, { type: 'browser' | 'ios' | 'android'; capabilities: any; isAttached: boolean }>;\n} = {\n browsers: new Map<string, WebdriverIO.Browser>(),\n currentSession: null,\n sessionMetadata: new Map(),\n};\n\nexport const getBrowser = () => {\n const browser = state.browsers.get(state.currentSession);\n if (!browser) {\n throw new Error('No active browser session');\n }\n return browser;\n};\n// Export state for app-session.tool.ts to access\n(getBrowser as any).__state = state;\n\nexport const startBrowserTool: ToolCallback = async ({\n headless = false,\n windowWidth = 1920,\n windowHeight = 1080,\n navigationUrl\n}: {\n headless?: boolean;\n windowWidth?: number;\n windowHeight?: number;\n navigationUrl?: string;\n}): Promise<CallToolResult> => {\n const chromeArgs = [\n `--window-size=${windowWidth},${windowHeight}`,\n '--no-sandbox',\n '--disable-search-engine-choice-screen',\n '--disable-infobars',\n '--log-level=3',\n '--use-fake-device-for-media-stream',\n '--use-fake-ui-for-media-stream',\n '--disable-web-security',\n '--allow-running-insecure-content',\n ];\n\n // Add headless argument if enabled\n if (headless) {\n chromeArgs.push('--headless=new');\n chromeArgs.push('--disable-gpu');\n chromeArgs.push('--disable-dev-shm-usage');\n }\n\n const browser = await remote({\n capabilities: {\n browserName: 'chrome',\n 'goog:chromeOptions': {\n args: chromeArgs,\n },\n acceptInsecureCerts: true,\n },\n });\n\n const { sessionId } = browser;\n state.browsers.set(sessionId, browser);\n state.currentSession = sessionId;\n state.sessionMetadata.set(sessionId, {\n type: 'browser',\n capabilities: browser.capabilities,\n isAttached: false,\n });\n\n // Navigate to URL if provided\n if (navigationUrl) {\n await browser.url(navigationUrl);\n }\n\n const modeText = headless ? 'headless' : 'headed';\n const urlText = navigationUrl ? ` and navigated to ${navigationUrl}` : '';\n return {\n content: [{\n type: 'text',\n text: `Browser started in ${modeText} mode with sessionId: ${sessionId} (${windowWidth}x${windowHeight})${urlText}`,\n }],\n };\n};\n\nexport const closeSessionTool: ToolCallback = async (args: { detach?: boolean } = {}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const sessionId = state.currentSession;\n const metadata = state.sessionMetadata.get(sessionId);\n\n // Only delete session if not detaching\n if (!args.detach) {\n await browser.deleteSession();\n }\n\n // Always clean up local state\n state.browsers.delete(sessionId);\n state.sessionMetadata.delete(sessionId);\n state.currentSession = null;\n\n const action = args.detach ? 'detached from' : 'closed';\n const note = args.detach && !metadata?.isAttached\n ? '\\nNote: Session will remain active on Appium server.'\n : '';\n\n return {\n content: [{ type: 'text', text: `Session ${sessionId} ${action}${note}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error closing session: ${e}` }],\n };\n }\n};","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\n\nexport const navigateToolDefinition: ToolDefinition = {\n name: 'navigate',\n description: 'navigates to a URL',\n inputSchema: {\n url: z.string().min(1).describe('The URL to navigate to'),\n },\n};\n\nexport const navigateTool: ToolCallback = async ({ url}: { url: string }) => {\n try {\n const browser = getBrowser();\n await browser.url(url);\n return {\n content: [{ type: 'text', text: `Navigated to ${url}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error navigating: ${e}` }],\n };\n }\n};\n","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\n\nconst defaultTimeout: number = 3000;\n\nexport const clickToolDefinition: ToolDefinition = {\n name: 'click_element',\n description: 'clicks an element',\n inputSchema: {\n selector: z.string().describe('Value for the selector, in the form of css selector or xpath (\"button.my-class\" or \"//button[@class=\\'my-class\\']\" or \"button=Exact text with spaces\" or \"a*=Link containing text\")'),\n scrollToView: z.boolean().optional().describe('Whether to scroll the element into view before clicking').default(true),\n timeout: z.number().optional().describe('Maximum time to wait for element in milliseconds'),\n },\n};\n\nconst clickAction = async (selector: string, timeout: number, scrollToView = true): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n await browser.waitUntil(browser.$(selector).isExisting, { timeout });\n if (scrollToView) {\n await browser.$(selector).scrollIntoView({ block: 'center', inline: 'center' });\n }\n await browser.$(selector).click();\n return {\n content: [{ type: 'text', text: `Element clicked (selector: ${selector})` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error clicking element: ${e}` }],\n };\n }\n};\n\nexport const clickTool: ToolCallback = async ({ selector, scrollToView, timeout = defaultTimeout}: {\n selector: string;\n scrollToView?: boolean;\n timeout?: number\n}): Promise<CallToolResult> => clickAction(selector, timeout, scrollToView);\n","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\n\nconst defaultTimeout: number = 3000;\n\nexport const setValueToolDefinition: ToolDefinition = {\n name: 'set_value',\n description: 'set value to an element, aka typing',\n inputSchema: {\n selector: z.string().describe('Value for the selector, in the form of css selector or xpath (\"button.my-class\" or \"//button[@class=\\'my-class\\']\")'),\n value: z.string().describe('Text to enter into the element'),\n scrollToView: z.boolean().optional().describe('Whether to scroll the element into view before typing').default(true),\n timeout: z.number().optional().describe('Maximum time to wait for element in milliseconds'),\n },\n};\n\nexport const setValueTool: ToolCallback = async ({ selector, value, scrollToView = true, timeout = defaultTimeout}: {\n selector: string;\n value: string;\n scrollToView?: boolean;\n timeout?: number\n}) => {\n try {\n const browser = getBrowser();\n await browser.waitUntil(browser.$(selector).isExisting, { timeout });\n if (scrollToView) {\n await browser.$(selector).scrollIntoView({ block: 'center', inline: 'center' });\n }\n await browser.$(selector).clearValue();\n await browser.$(selector).setValue(value);\n return {\n content: [{ type: 'text', text: `Text \"${value}\" entered into element` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error entering text: ${e}` }],\n };\n }\n};","import { remote } from 'webdriverio';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { buildAndroidCapabilities, buildIOSCapabilities, getAppiumServerConfig, } from '../config/appium.config';\nimport { getBrowser } from './browser.tool';\n\nexport const startAppToolDefinition: ToolDefinition = {\n name: 'start_app_session',\n description: 'starts a mobile app session (iOS/Android) via Appium',\n inputSchema: {\n platform: z.enum(['iOS', 'Android']).describe('Mobile platform'),\n appPath: z.string().optional().describe('Path to the app file (.app/.apk/.ipa). Required unless noReset=true (connecting to already-running app)'),\n deviceName: z.string().describe('Device/emulator/simulator name'),\n platformVersion: z.string().optional().describe('OS version (e.g., \"17.0\", \"14\")'),\n automationName: z\n .enum(['XCUITest', 'UiAutomator2', 'Espresso'])\n .optional()\n .describe('Automation driver name'),\n appiumHost: z.string().optional().describe('Appium server hostname (overrides APPIUM_URL env var)'),\n appiumPort: z.number().optional().describe('Appium server port (overrides APPIUM_URL_PORT env var)'),\n appiumPath: z.string().optional().describe('Appium server path (overrides APPIUM_PATH env var)'),\n autoGrantPermissions: z.boolean().optional().describe('Auto-grant app permissions (default: true)'),\n autoAcceptAlerts: z.boolean().optional().describe('Auto-accept alerts (default: true)'),\n autoDismissAlerts: z.boolean().optional().describe('Auto-dismiss alerts (default: false, will override \"autoAcceptAlerts\" to undefined if set)'),\n appWaitActivity: z.string().optional().describe('Activity to wait for on launch (Android only)'),\n udid: z.string().optional().describe('Unique Device Identifier for iOS real device testing (e.g., \"00008030-001234567890002E\")'),\n noReset: z.boolean().optional().describe('Do not reset app state before session (preserves app data). Default: false'),\n fullReset: z.boolean().optional().describe('Uninstall app before/after session. Default: true. Set to false with noReset=true to preserve app state completely'),\n newCommandTimeout: z.number().min(0).optional().describe('How long (in seconds) Appium will wait for a new command before assuming the client has quit and ending the session. Default: 60. Set to 300 for 5 minutes, etc.'),\n },\n};\n\n// Access shared state from browser.tool.ts\nexport const getState = () => {\n const sharedState = (getBrowser as any).__state;\n if (!sharedState) {\n throw new Error('Browser state not initialized');\n }\n return sharedState as {\n browsers: Map<string, WebdriverIO.Browser>;\n currentSession: string | null;\n sessionMetadata: Map<string, { type: 'browser' | 'ios' | 'android'; capabilities: any; isAttached: boolean }>;\n };\n};\n\nexport const startAppTool: ToolCallback = async (args: {\n platform: 'iOS' | 'Android';\n appPath?: string;\n deviceName: string;\n platformVersion?: string;\n automationName?: 'XCUITest' | 'UiAutomator2' | 'Espresso';\n appiumHost?: string;\n appiumPort?: number;\n appiumPath?: string;\n autoGrantPermissions?: boolean;\n autoAcceptAlerts?: boolean;\n autoDismissAlerts?: boolean;\n appWaitActivity?: string;\n udid?: string;\n noReset?: boolean;\n fullReset?: boolean;\n newCommandTimeout?: number;\n}): Promise<CallToolResult> => {\n try {\n const {\n platform,\n appPath,\n deviceName,\n platformVersion,\n automationName,\n appiumHost,\n appiumPort,\n appiumPath,\n autoGrantPermissions = true,\n autoAcceptAlerts,\n autoDismissAlerts,\n appWaitActivity,\n udid,\n noReset,\n fullReset,\n newCommandTimeout,\n } = args;\n\n // Validate: either appPath or noReset=true is required\n if (!appPath && noReset !== true) {\n return {\n content: [{\n type: 'text',\n text: 'Error: Either \"appPath\" must be provided to install an app, or \"noReset: true\" must be set to connect to an already-running app.',\n }],\n };\n }\n\n // Get Appium server configuration\n const serverConfig = getAppiumServerConfig({\n hostname: appiumHost,\n port: appiumPort,\n path: appiumPath,\n });\n\n // Build platform-specific capabilities\n const capabilities: Record<string, any> = platform === 'iOS'\n ? buildIOSCapabilities(appPath, {\n deviceName,\n platformVersion,\n automationName: (automationName as 'XCUITest') || 'XCUITest',\n autoGrantPermissions,\n autoAcceptAlerts,\n autoDismissAlerts,\n udid,\n noReset,\n fullReset,\n newCommandTimeout,\n })\n : buildAndroidCapabilities(appPath, {\n deviceName,\n platformVersion,\n automationName: (automationName as 'UiAutomator2' | 'Espresso') || 'UiAutomator2',\n autoGrantPermissions,\n autoAcceptAlerts,\n autoDismissAlerts,\n appWaitActivity,\n noReset,\n fullReset,\n newCommandTimeout,\n });\n\n // Create Appium session\n const browser = await remote({\n protocol: 'http',\n hostname: serverConfig.hostname,\n port: serverConfig.port,\n path: serverConfig.path,\n capabilities,\n });\n\n const { sessionId } = browser;\n\n // Store session and metadata\n // Auto-set isAttached=true when noReset or no appPath to preserve session on close\n const shouldAutoDetach = noReset === true || !appPath;\n const state = getState();\n state.browsers.set(sessionId, browser);\n state.currentSession = sessionId;\n state.sessionMetadata.set(sessionId, {\n type: platform.toLowerCase() as 'ios' | 'android',\n capabilities,\n isAttached: shouldAutoDetach,\n });\n\n const appInfo = appPath ? `\\nApp: ${appPath}` : '\\nApp: (connected to running app)';\n const detachNote = shouldAutoDetach\n ? '\\n\\n(Auto-detach enabled: session will be preserved on close. Use close_session({ detach: false }) to force terminate.)'\n : '';\n return {\n content: [\n {\n type: 'text',\n text: `${platform} app session started with sessionId: ${sessionId}\\nDevice: ${deviceName}${appInfo}\\nAppium Server: ${serverConfig.hostname}:${serverConfig.port}${serverConfig.path}${detachNote}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error starting app session: ${e}` }],\n };\n }\n};\n\n","/**\n * Appium server configuration and capability builders\n */\n\nexport interface AppiumServerConfig {\n hostname: string;\n port: number;\n path: string;\n}\n\nexport interface IOSCapabilityOptions {\n deviceName: string;\n platformVersion?: string;\n automationName?: 'XCUITest';\n autoGrantPermissions?: boolean;\n autoAcceptAlerts?: boolean;\n autoDismissAlerts?: boolean;\n udid?: string;\n noReset?: boolean;\n fullReset?: boolean;\n newCommandTimeout?: number;\n\n [key: string]: any;\n}\n\nexport interface AndroidCapabilityOptions {\n deviceName: string;\n platformVersion?: string;\n automationName?: 'UiAutomator2' | 'Espresso';\n autoGrantPermissions?: boolean;\n autoAcceptAlerts?: boolean;\n autoDismissAlerts?: boolean;\n appWaitActivity?: string;\n noReset?: boolean;\n fullReset?: boolean;\n newCommandTimeout?: number;\n\n [key: string]: any;\n}\n\n/**\n * Get Appium server configuration from environment variables or defaults\n */\nexport function getAppiumServerConfig(overrides?: Partial<AppiumServerConfig>): AppiumServerConfig {\n return {\n hostname: overrides?.hostname || process.env.APPIUM_URL || '127.0.0.1',\n port: overrides?.port || Number(process.env.APPIUM_URL_PORT) || 4723,\n path: overrides?.path || process.env.APPIUM_PATH || '/',\n };\n}\n\n/**\n * Build iOS capabilities for Appium session\n */\nexport function buildIOSCapabilities(\n appPath: string | undefined,\n options: IOSCapabilityOptions,\n): Record<string, any> {\n const capabilities: Record<string, any> = {\n platformName: 'iOS',\n 'appium:platformVersion': options.platformVersion,\n 'appium:deviceName': options.deviceName,\n 'appium:automationName': options.automationName || 'XCUITest',\n };\n\n // Only set app path if provided (allows connecting to already-running app)\n if (appPath) {\n capabilities['appium:app'] = appPath;\n }\n\n // Set UDID for real device testing (required for physical iOS devices)\n if (options.udid) {\n capabilities['appium:udid'] = options.udid;\n }\n\n // Set reset behavior (for preserving app state)\n if (options.noReset !== undefined) {\n capabilities['appium:noReset'] = options.noReset;\n }\n if (options.fullReset !== undefined) {\n capabilities['appium:fullReset'] = options.fullReset;\n }\n\n // Set session timeout (how long Appium waits for new commands)\n if (options.newCommandTimeout !== undefined) {\n capabilities['appium:newCommandTimeout'] = options.newCommandTimeout;\n }\n\n capabilities['appium:autoGrantPermissions'] = options.autoGrantPermissions ?? true;\n capabilities['appium:autoAcceptAlerts'] = options.autoAcceptAlerts ?? true;\n\n if (options.autoDismissAlerts !== undefined) {\n capabilities['appium:autoDismissAlerts'] = options.autoDismissAlerts;\n capabilities['appium:autoAcceptAlerts'] = undefined;\n }\n\n // Add any additional custom options\n for (const [key, value] of Object.entries(options)) {\n if (\n !['deviceName', 'platformVersion', 'automationName', 'autoAcceptAlerts', 'autoDismissAlerts', 'udid', 'noReset', 'fullReset', 'newCommandTimeout'].includes(\n key,\n )\n ) {\n capabilities[`appium:${key}`] = value;\n }\n }\n\n return capabilities;\n}\n\n/**\n * Build Android capabilities for Appium session\n */\nexport function buildAndroidCapabilities(\n appPath: string | undefined,\n options: AndroidCapabilityOptions,\n): Record<string, any> {\n const capabilities: Record<string, any> = {\n platformName: 'Android',\n 'appium:platformVersion': options.platformVersion,\n 'appium:deviceName': options.deviceName,\n 'appium:automationName': options.automationName || 'UiAutomator2',\n };\n\n // Only set app path if provided (allows connecting to already-running app)\n if (appPath) {\n capabilities['appium:app'] = appPath;\n }\n\n // Set reset behavior (for preserving app state)\n if (options.noReset !== undefined) {\n capabilities['appium:noReset'] = options.noReset;\n }\n if (options.fullReset !== undefined) {\n capabilities['appium:fullReset'] = options.fullReset;\n }\n\n // Set session timeout (how long Appium waits for new commands)\n if (options.newCommandTimeout !== undefined) {\n capabilities['appium:newCommandTimeout'] = options.newCommandTimeout;\n }\n\n // Optional Android-specific settings\n capabilities['appium:autoGrantPermissions'] = options.autoGrantPermissions ?? true;\n capabilities['appium:autoAcceptAlerts'] = options.autoAcceptAlerts ?? true;\n\n if (options.autoDismissAlerts !== undefined) {\n capabilities['appium:autoDismissAlerts'] = options.autoDismissAlerts;\n capabilities['appium:autoAcceptAlerts'] = undefined;\n }\n\n if (options.appWaitActivity) {\n capabilities['appium:appWaitActivity'] = options.appWaitActivity;\n }\n\n // Add any additional custom options\n for (const [key, value] of Object.entries(options)) {\n if (\n !['deviceName', 'platformVersion', 'automationName', 'autoGrantPermissions', 'appWaitActivity', 'noReset', 'fullReset', 'newCommandTimeout'].includes(\n key,\n )\n ) {\n capabilities[`appium:${key}`] = value;\n }\n }\n\n return capabilities;\n}\n","import { getBrowser } from './browser.tool';\nimport { getState } from './app-session.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\n\nexport const scrollToolDefinition: ToolDefinition = {\n name: 'scroll',\n description: 'scrolls the page by specified pixels (browser only). For mobile, use the swipe tool.',\n inputSchema: {\n direction: z.enum(['up', 'down']).describe('Scroll direction'),\n pixels: z.number().optional().default(500).describe('Number of pixels to scroll'),\n },\n};\n\nexport const scrollTool: ToolCallback = async ({ direction, pixels = 500 }: { direction: 'up' | 'down'; pixels?: number }) => {\n try {\n const browser = getBrowser();\n const state = getState();\n const metadata = state.sessionMetadata.get(state.currentSession);\n const sessionType = metadata?.type;\n\n if (sessionType !== 'browser') {\n throw new Error('scroll only works in browser sessions. For mobile, use the swipe tool.');\n }\n\n const scrollAmount = direction === 'down' ? pixels : -pixels;\n await browser.execute((amount) => {\n window.scrollBy(0, amount);\n }, scrollAmount);\n\n return {\n content: [{ type: 'text', text: `Scrolled ${direction} ${pixels} pixels` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error scrolling: ${e}` }],\n };\n }\n};","/**\n * Browser script to get visible elements on the page\n * Supports interactable elements, visual elements, or both\n *\n * @param elementType - Type of elements to return: 'interactable', 'visual', or 'all'\n */\nconst elementsScript = (elementType: 'interactable' | 'visual' | 'all' = 'interactable') => (function () {\n const interactableSelectors = [\n 'a[href]', // Links with href\n 'button', // Buttons\n 'input:not([type=\"hidden\"])', // Input fields (except hidden)\n 'select', // Select dropdowns\n 'textarea', // Text areas\n '[role=\"button\"]', // Elements with button role\n '[role=\"link\"]', // Elements with link role\n '[role=\"checkbox\"]', // Elements with checkbox role\n '[role=\"radio\"]', // Elements with radio role\n '[role=\"tab\"]', // Elements with tab role\n '[role=\"menuitem\"]', // Elements with menuitem role\n '[role=\"combobox\"]', // Elements with combobox role\n '[role=\"option\"]', // Elements with option role\n '[role=\"switch\"]', // Elements with switch role\n '[role=\"slider\"]', // Elements with slider role\n '[role=\"textbox\"]', // Elements with textbox role\n '[role=\"searchbox\"]', // Elements with searchbox role\n '[contenteditable=\"true\"]', // Editable content\n '[tabindex]:not([tabindex=\"-1\"])', // Elements with tabindex\n ];\n\n const visualSelectors = [\n 'img', // Images\n 'picture', // Picture elements\n 'svg', // SVG graphics\n 'video', // Video elements\n 'canvas', // Canvas elements\n '[style*=\"background-image\"]', // Elements with background images\n ];\n\n /**\n * Check if an element is visible\n * @param {HTMLElement} element - The element to check\n * @returns {boolean} - Whether the element is visible\n */\n function isVisible(element: HTMLElement) {\n // Use checkVisibility if available (modern browsers)\n if (typeof element.checkVisibility === 'function') {\n return element.checkVisibility({\n opacityProperty: true,\n visibilityProperty: true,\n contentVisibilityAuto: true,\n });\n }\n\n // Fallback for browsers that don't support checkVisibility\n const style = window.getComputedStyle(element);\n return style.display !== 'none' &&\n style.visibility !== 'hidden' &&\n style.opacity !== '0' &&\n element.offsetWidth > 0 &&\n element.offsetHeight > 0;\n }\n\n /**\n * Get a CSS selector for an element\n * @param {HTMLElement} element - The element to get a selector for\n * @returns {string} - The CSS selector\n */\n function getCssSelector(element: HTMLElement) {\n if (element.id) {\n return `#${CSS.escape(element.id)}`;\n }\n\n // Try to build a selector with classes if available\n if (element.className && typeof element.className === 'string') {\n const classes = element.className.trim().split(/\\s+/).filter(Boolean);\n if (classes.length > 0) {\n // Use up to 2 classes to avoid overly complex selectors\n const classSelector = classes.slice(0, 2).map(c => `.${CSS.escape(c)}`).join('');\n const tagWithClass = `${element.tagName.toLowerCase()}${classSelector}`;\n\n // Check if this selector uniquely identifies the element\n if (document.querySelectorAll(tagWithClass).length === 1) {\n return tagWithClass;\n }\n }\n }\n\n // Build a path-based selector\n let current: HTMLElement | null = element;\n const path = [];\n\n while (current && current !== document.documentElement) {\n let selector = current.tagName.toLowerCase();\n\n // Add ID if available\n if (current.id) {\n selector = `#${CSS.escape(current.id)}`;\n path.unshift(selector);\n break;\n }\n\n // Add position among siblings\n const parent = current.parentElement;\n if (parent) {\n const siblings = Array.from(parent.children).filter(child =>\n child.tagName === current!.tagName,\n );\n\n if (siblings.length > 1) {\n const index = siblings.indexOf(current) + 1;\n selector += `:nth-child(${index})`;\n }\n }\n\n path.unshift(selector);\n current = current.parentElement;\n\n // Limit path length to avoid overly complex selectors\n if (path.length >= 4) {\n break;\n }\n }\n\n return path.join(' > ');\n }\n\n /**\n * Get all visible elements on the page based on elementType\n * @returns {Record<string, unknown>[]} - Array of element information objects\n */\n function getElements(): Record<string, unknown>[] {\n // Select which selectors to use based on elementType\n const selectors: string[] = [];\n if (elementType === 'interactable' || elementType === 'all') {\n selectors.push(...interactableSelectors);\n }\n if (elementType === 'visual' || elementType === 'all') {\n selectors.push(...visualSelectors);\n }\n\n // Get all potentially matching elements\n const allElements: Element[] = [];\n selectors.forEach(selector => {\n const elements = document.querySelectorAll(selector);\n elements.forEach(element => {\n if (!allElements.includes(element)) {\n allElements.push(element);\n }\n });\n });\n\n // Filter for visible elements and collect information\n const elementInfos = allElements\n .filter(element => isVisible(element as HTMLElement) && !(element as HTMLInputElement).disabled)\n .map(element => {\n const el = element as HTMLElement;\n const inputEl = element as HTMLInputElement;\n\n // Get element information\n const rect = el.getBoundingClientRect();\n const isInViewport = (\n rect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&\n rect.right <= (window.innerWidth || document.documentElement.clientWidth)\n );\n\n // Build object with ALL fields for uniform schema (enables TOON tabular format)\n // Empty string '' used for missing values, post-processed to bare commas\n const info: Record<string, unknown> = {\n tagName: el.tagName.toLowerCase(),\n type: el.getAttribute('type') || '',\n id: el.id || '',\n className: (typeof el.className === 'string' ? el.className : '') || '',\n textContent: el.textContent?.trim() || '',\n value: inputEl.value || '',\n placeholder: inputEl.placeholder || '',\n href: el.getAttribute('href') || '',\n ariaLabel: el.getAttribute('aria-label') || '',\n role: el.getAttribute('role') || '',\n src: el.getAttribute('src') || '',\n alt: el.getAttribute('alt') || '',\n cssSelector: getCssSelector(el),\n isInViewport: isInViewport,\n };\n\n return info;\n });\n\n return elementInfos;\n }\n\n return getElements();\n})();\n\nexport default elementsScript;","/**\n * XML page source parsing utilities\n * Converts Appium page source XML to traversable JSON tree\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/source-parsing.ts\n */\n\nimport { DOMParser } from '@xmldom/xmldom';\n\nexport interface ElementAttributes {\n // Android attributes\n 'resource-id'?: string;\n 'content-desc'?: string;\n text?: string;\n class?: string;\n package?: string;\n clickable?: string;\n 'long-clickable'?: string;\n focusable?: string;\n checkable?: string;\n scrollable?: string;\n enabled?: string;\n displayed?: string;\n bounds?: string; // Format: \"[x1,y1][x2,y2]\"\n\n // iOS attributes\n type?: string;\n name?: string;\n label?: string;\n value?: string;\n accessible?: string;\n visible?: string;\n x?: string;\n y?: string;\n width?: string;\n height?: string;\n\n // Generic\n [key: string]: string | undefined;\n}\n\nexport interface JSONElement {\n children: JSONElement[];\n tagName: string;\n attributes: ElementAttributes;\n path: string; // Dot-separated index path for tree traversal\n}\n\n/**\n * Get child nodes that are elements (not text nodes, comments, etc.)\n */\nfunction childNodesOf(node: Node): Node[] {\n const children: Node[] = [];\n if (node.childNodes) {\n for (let i = 0; i < node.childNodes.length; i++) {\n const child = node.childNodes.item(i);\n if (child?.nodeType === 1) {\n // ELEMENT_NODE\n children.push(child);\n }\n }\n }\n return children;\n}\n\n/**\n * Recursively translate DOM node to JSONElement\n */\nfunction translateRecursively(\n domNode: Node,\n parentPath: string = '',\n index: number | null = null,\n): JSONElement {\n const attributes: ElementAttributes = {};\n\n // Extract attributes if this is an element node\n const element = domNode as Element;\n if (element.attributes) {\n for (let attrIdx = 0; attrIdx < element.attributes.length; attrIdx++) {\n const attr = element.attributes.item(attrIdx);\n if (attr) {\n // Replace newlines in attribute values\n attributes[attr.name] = attr.value.replace(/(\\n)/gm, '\\\\n');\n }\n }\n }\n\n // Build path: dot-separated index chain (e.g., \"0.2.1\")\n const path = index === null ? '' : `${parentPath ? parentPath + '.' : ''}${index}`;\n\n return {\n children: childNodesOf(domNode).map((childNode, childIndex) =>\n translateRecursively(childNode, path, childIndex),\n ),\n tagName: domNode.nodeName,\n attributes,\n path,\n };\n}\n\n/**\n * Convert XML page source to JSON tree structure\n * @param sourceXML - The XML string from getPageSource()\n * @returns JSONElement tree or null if parsing fails\n */\nexport function xmlToJSON(sourceXML: string): JSONElement | null {\n try {\n const parser = new DOMParser();\n const sourceDoc = parser.parseFromString(sourceXML, 'text/xml');\n\n // Handle parsing errors\n const parseErrors = sourceDoc.getElementsByTagName('parsererror');\n if (parseErrors.length > 0) {\n console.error('[xmlToJSON] XML parsing error:', parseErrors[0].textContent);\n return null;\n }\n\n // Get the first element child\n const children = childNodesOf(sourceDoc);\n const firstChild =\n children[0] ||\n (sourceDoc.documentElement ? childNodesOf(sourceDoc.documentElement)[0] : null);\n\n return firstChild\n ? translateRecursively(firstChild)\n : { children: [], tagName: '', attributes: {}, path: '' };\n } catch (e) {\n console.error('[xmlToJSON] Failed to parse XML:', e);\n return null;\n }\n}\n\n/**\n * Parse Android bounds string \"[x1,y1][x2,y2]\" to coordinates\n * @param bounds - Bounds string in format \"[x1,y1][x2,y2]\"\n * @returns Object with x, y, width, height\n */\nexport function parseAndroidBounds(bounds: string): {\n x: number;\n y: number;\n width: number;\n height: number;\n} {\n const match = bounds.match(/\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]/);\n if (!match) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n\n const x1 = parseInt(match[1], 10);\n const y1 = parseInt(match[2], 10);\n const x2 = parseInt(match[3], 10);\n const y2 = parseInt(match[4], 10);\n\n return {\n x: x1,\n y: y1,\n width: x2 - x1,\n height: y2 - y1,\n };\n}\n\n/**\n * Parse iOS element bounds from individual x, y, width, height attributes\n * @param attributes - Element attributes\n * @returns Object with x, y, width, height\n */\nexport function parseIOSBounds(attributes: ElementAttributes): {\n x: number;\n y: number;\n width: number;\n height: number;\n} {\n return {\n x: parseInt(attributes.x || '0', 10),\n y: parseInt(attributes.y || '0', 10),\n width: parseInt(attributes.width || '0', 10),\n height: parseInt(attributes.height || '0', 10),\n };\n}\n\n/**\n * Flatten JSON element tree to array (depth-first)\n * @param root - Root JSONElement\n * @returns Array of all elements in tree\n */\nexport function flattenElementTree(root: JSONElement): JSONElement[] {\n const result: JSONElement[] = [];\n\n function traverse(element: JSONElement) {\n result.push(element);\n for (const child of element.children) {\n traverse(child);\n }\n }\n\n traverse(root);\n return result;\n}\n\n/**\n * Count occurrences of an attribute value in the source XML\n * Used to determine if a selector would be unique\n */\nexport function countAttributeOccurrences(\n sourceXML: string,\n attribute: string,\n value: string,\n): number {\n // Escape special regex characters in value\n const escapedValue = value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n // Match attribute=\"value\" pattern\n const pattern = new RegExp(`${attribute}=[\"']${escapedValue}[\"']`, 'g');\n const matches = sourceXML.match(pattern);\n return matches ? matches.length : 0;\n}\n\n/**\n * Check if an attribute value is unique in the source\n */\nexport function isAttributeUnique(\n sourceXML: string,\n attribute: string,\n value: string,\n): boolean {\n return countAttributeOccurrences(sourceXML, attribute, value) === 1;\n}\n","/**\n * Element filtering logic for mobile platforms\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/element-filter.ts\n */\n\nimport type { JSONElement } from './source-parsing';\n\nexport interface FilterOptions {\n includeTagNames?: string[]; // Only include these tags (whitelist)\n excludeTagNames?: string[]; // Exclude these tags (blacklist)\n requireAttributes?: string[]; // Must have at least one of these attributes\n minAttributeCount?: number; // Minimum number of non-empty attributes\n fetchableOnly?: boolean; // Only interactable elements\n clickableOnly?: boolean; // Only elements with clickable=\"true\"\n visibleOnly?: boolean; // Only visible/displayed elements\n}\n\n/**\n * Android interactive element types\n */\nexport const ANDROID_INTERACTABLE_TAGS = [\n // Input elements\n 'android.widget.EditText',\n 'android.widget.AutoCompleteTextView',\n 'android.widget.MultiAutoCompleteTextView',\n 'android.widget.SearchView',\n\n // Button-like elements\n 'android.widget.Button',\n 'android.widget.ImageButton',\n 'android.widget.ToggleButton',\n 'android.widget.CompoundButton',\n 'android.widget.RadioButton',\n 'android.widget.CheckBox',\n 'android.widget.Switch',\n 'android.widget.FloatingActionButton',\n 'com.google.android.material.button.MaterialButton',\n 'com.google.android.material.floatingactionbutton.FloatingActionButton',\n\n // Text elements (often tappable)\n 'android.widget.TextView',\n 'android.widget.CheckedTextView',\n\n // Image elements (often tappable)\n 'android.widget.ImageView',\n 'android.widget.QuickContactBadge',\n\n // Selection elements\n 'android.widget.Spinner',\n 'android.widget.SeekBar',\n 'android.widget.RatingBar',\n 'android.widget.ProgressBar',\n 'android.widget.DatePicker',\n 'android.widget.TimePicker',\n 'android.widget.NumberPicker',\n\n // List/grid items\n 'android.widget.AdapterView',\n];\n\n/**\n * iOS interactive element types\n */\nexport const IOS_INTERACTABLE_TAGS = [\n // Input elements\n 'XCUIElementTypeTextField',\n 'XCUIElementTypeSecureTextField',\n 'XCUIElementTypeTextView',\n 'XCUIElementTypeSearchField',\n\n // Button-like elements\n 'XCUIElementTypeButton',\n 'XCUIElementTypeLink',\n\n // Text elements (often tappable)\n 'XCUIElementTypeStaticText',\n\n // Image elements\n 'XCUIElementTypeImage',\n 'XCUIElementTypeIcon',\n\n // Selection elements\n 'XCUIElementTypeSwitch',\n 'XCUIElementTypeSlider',\n 'XCUIElementTypeStepper',\n 'XCUIElementTypeSegmentedControl',\n 'XCUIElementTypePicker',\n 'XCUIElementTypePickerWheel',\n 'XCUIElementTypeDatePicker',\n 'XCUIElementTypePageIndicator',\n\n // Table/list items\n 'XCUIElementTypeCell',\n 'XCUIElementTypeMenuItem',\n 'XCUIElementTypeMenuBarItem',\n\n // Toggle elements\n 'XCUIElementTypeCheckBox',\n 'XCUIElementTypeRadioButton',\n 'XCUIElementTypeToggle',\n\n // Other interactive\n 'XCUIElementTypeKey',\n 'XCUIElementTypeKeyboard',\n 'XCUIElementTypeAlert',\n 'XCUIElementTypeSheet',\n];\n\n/**\n * Android layout containers - typically not interactive targets\n */\nexport const ANDROID_LAYOUT_CONTAINERS = [\n // Core ViewGroup classes\n 'android.view.ViewGroup',\n 'android.view.View',\n 'android.widget.FrameLayout',\n 'android.widget.LinearLayout',\n 'android.widget.RelativeLayout',\n 'android.widget.GridLayout',\n 'android.widget.TableLayout',\n 'android.widget.TableRow',\n 'android.widget.AbsoluteLayout',\n\n // AndroidX layout classes\n 'androidx.constraintlayout.widget.ConstraintLayout',\n 'androidx.coordinatorlayout.widget.CoordinatorLayout',\n 'androidx.appcompat.widget.LinearLayoutCompat',\n 'androidx.cardview.widget.CardView',\n 'androidx.appcompat.widget.ContentFrameLayout',\n 'androidx.appcompat.widget.FitWindowsFrameLayout',\n\n // Scrolling containers\n 'android.widget.ScrollView',\n 'android.widget.HorizontalScrollView',\n 'android.widget.NestedScrollView',\n 'androidx.core.widget.NestedScrollView',\n 'androidx.recyclerview.widget.RecyclerView',\n 'android.widget.ListView',\n 'android.widget.GridView',\n 'android.widget.AbsListView',\n\n // App chrome / system elements\n 'android.widget.ActionBarContainer',\n 'android.widget.ActionBarOverlayLayout',\n 'android.view.ViewStub',\n 'androidx.appcompat.widget.ActionBarContainer',\n 'androidx.appcompat.widget.ActionBarContextView',\n 'androidx.appcompat.widget.ActionBarOverlayLayout',\n\n // Decor views\n 'com.android.internal.policy.DecorView',\n 'android.widget.DecorView',\n];\n\n/**\n * iOS layout containers - typically not interactive targets\n */\nexport const IOS_LAYOUT_CONTAINERS = [\n // Generic containers\n 'XCUIElementTypeOther',\n 'XCUIElementTypeGroup',\n 'XCUIElementTypeLayoutItem',\n\n // Scroll containers\n 'XCUIElementTypeScrollView',\n 'XCUIElementTypeTable',\n 'XCUIElementTypeCollectionView',\n 'XCUIElementTypeScrollBar',\n\n // Navigation chrome\n 'XCUIElementTypeNavigationBar',\n 'XCUIElementTypeTabBar',\n 'XCUIElementTypeToolbar',\n 'XCUIElementTypeStatusBar',\n 'XCUIElementTypeMenuBar',\n\n // Windows and views\n 'XCUIElementTypeWindow',\n 'XCUIElementTypeSheet',\n 'XCUIElementTypeDrawer',\n 'XCUIElementTypeDialog',\n 'XCUIElementTypePopover',\n 'XCUIElementTypePopUpButton',\n\n // Outline elements\n 'XCUIElementTypeOutline',\n 'XCUIElementTypeOutlineRow',\n 'XCUIElementTypeBrowser',\n 'XCUIElementTypeSplitGroup',\n 'XCUIElementTypeSplitter',\n\n // Application root\n 'XCUIElementTypeApplication',\n];\n\n/**\n * Check if element tag matches any in the list (handles partial matches)\n */\nfunction matchesTagList(tagName: string, tagList: string[]): boolean {\n // Exact match\n if (tagList.includes(tagName)) {\n return true;\n }\n\n // Partial match for tags with package prefixes\n for (const tag of tagList) {\n if (tagName.endsWith(tag) || tagName.includes(tag)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if element matches tag name filters\n */\nfunction matchesTagFilters(\n element: JSONElement,\n includeTagNames: string[],\n excludeTagNames: string[],\n): boolean {\n // If include list provided, element must match it\n if (includeTagNames.length > 0 && !matchesTagList(element.tagName, includeTagNames)) {\n return false;\n }\n\n // If element matches exclude list, filter it out\n if (matchesTagList(element.tagName, excludeTagNames)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Check if element matches attribute-based filters\n */\nfunction matchesAttributeFilters(\n element: JSONElement,\n requireAttributes: string[],\n minAttributeCount: number,\n): boolean {\n // Check required attributes\n if (requireAttributes.length > 0) {\n const hasRequiredAttr = requireAttributes.some((attr) => element.attributes?.[attr]);\n if (!hasRequiredAttr) return false;\n }\n\n // Check minimum attribute count\n if (element.attributes && minAttributeCount > 0) {\n const attrCount = Object.values(element.attributes).filter(\n (v) => v !== undefined && v !== null && v !== '',\n ).length;\n if (attrCount < minAttributeCount) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if element is interactable based on platform\n */\nexport function isInteractableElement(\n element: JSONElement,\n isNative: boolean,\n automationName: string,\n): boolean {\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n\n const interactableTags = isAndroid ? ANDROID_INTERACTABLE_TAGS : IOS_INTERACTABLE_TAGS;\n\n // Check if tag is interactable\n if (matchesTagList(element.tagName, interactableTags)) {\n return true;\n }\n\n // Check clickable/focusable attributes (Android)\n if (isAndroid) {\n if (\n element.attributes?.clickable === 'true' ||\n element.attributes?.focusable === 'true' ||\n element.attributes?.checkable === 'true' ||\n element.attributes?.['long-clickable'] === 'true'\n ) {\n return true;\n }\n }\n\n // Check accessible attribute (iOS)\n if (!isAndroid) {\n if (element.attributes?.accessible === 'true') {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Check if element is a layout container\n */\nexport function isLayoutContainer(element: JSONElement, platform: 'android' | 'ios'): boolean {\n const containerList = platform === 'android' ? ANDROID_LAYOUT_CONTAINERS : IOS_LAYOUT_CONTAINERS;\n return matchesTagList(element.tagName, containerList);\n}\n\n/**\n * Check if element has meaningful content (text, accessibility info)\n * Elements with content should be kept even if they're containers\n */\nexport function hasMeaningfulContent(\n element: JSONElement,\n platform: 'android' | 'ios',\n): boolean {\n const attrs = element.attributes;\n\n // Check for text content\n if (attrs.text && attrs.text.trim() !== '' && attrs.text !== 'null') {\n return true;\n }\n\n if (platform === 'android') {\n // Android: content-desc is accessibility info\n if (attrs['content-desc'] && attrs['content-desc'].trim() !== '' && attrs['content-desc'] !== 'null') {\n return true;\n }\n } else {\n // iOS: label or name is accessibility info\n if (attrs.label && attrs.label.trim() !== '' && attrs.label !== 'null') {\n return true;\n }\n if (attrs.name && attrs.name.trim() !== '' && attrs.name !== 'null') {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Determine if an element should be included based on all filter criteria\n */\nexport function shouldIncludeElement(\n element: JSONElement,\n filters: FilterOptions,\n isNative: boolean,\n automationName: string,\n): boolean {\n const {\n includeTagNames = [],\n excludeTagNames = ['hierarchy'], // Always exclude root hierarchy node\n requireAttributes = [],\n minAttributeCount = 0,\n fetchableOnly = false,\n clickableOnly = false,\n visibleOnly = true,\n } = filters;\n\n // Check tag name filters\n if (!matchesTagFilters(element, includeTagNames, excludeTagNames)) {\n return false;\n }\n\n // Check attribute filters\n if (!matchesAttributeFilters(element, requireAttributes, minAttributeCount)) {\n return false;\n }\n\n // Check clickable filter (Android only)\n if (clickableOnly && element.attributes?.clickable !== 'true') {\n return false;\n }\n\n // Check visible/displayed filter\n if (visibleOnly) {\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n if (isAndroid && element.attributes?.displayed === 'false') {\n return false;\n }\n if (!isAndroid && element.attributes?.visible === 'false') {\n return false;\n }\n }\n\n // Check fetchable/interactable filter\n if (fetchableOnly && !isInteractableElement(element, isNative, automationName)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Get default filter options for a platform\n */\nexport function getDefaultFilters(\n platform: 'android' | 'ios',\n includeContainers: boolean = false,\n): FilterOptions {\n const layoutContainers = platform === 'android' ? ANDROID_LAYOUT_CONTAINERS : IOS_LAYOUT_CONTAINERS;\n\n return {\n excludeTagNames: includeContainers ? ['hierarchy'] : ['hierarchy', ...layoutContainers],\n fetchableOnly: !includeContainers,\n visibleOnly: true,\n clickableOnly: false,\n };\n}\n","/**\n * Generate multiple locator strategies for an element\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/locator-generation.ts\n */\n\nimport type { JSONElement } from './source-parsing';\nimport { isAttributeUnique } from './source-parsing';\n\nexport type LocatorStrategy =\n | 'accessibility-id'\n | 'id'\n | 'class-name'\n | 'xpath'\n | 'predicate-string'\n | 'class-chain'\n | 'uiautomator'\n | 'text';\n\n/**\n * Check if a string value is valid for use in a locator\n */\nfunction isValidValue(value: string | undefined): value is string {\n return value !== undefined && value !== null && value !== 'null' && value.trim() !== '';\n}\n\n/**\n * Escape special characters in text for use in selectors\n */\nfunction escapeText(text: string): string {\n return text.replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n');\n}\n\n/**\n * Get simple locators based on single attributes\n * These are preferred because they're most stable and readable\n */\nfunction getSimpleSuggestedLocators(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): [LocatorStrategy, string][] {\n const results: [LocatorStrategy, string][] = [];\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n const attrs = element.attributes;\n\n if (isAndroid) {\n // Android simple locators\n\n // 1. Resource ID (most stable)\n const resourceId = attrs['resource-id'];\n if (isValidValue(resourceId) && isAttributeUnique(sourceXML, 'resource-id', resourceId)) {\n results.push(['id', `android=new UiSelector().resourceId(\"${resourceId}\")`]);\n }\n\n // 2. Content Description (accessibility)\n const contentDesc = attrs['content-desc'];\n if (isValidValue(contentDesc) && isAttributeUnique(sourceXML, 'content-desc', contentDesc)) {\n results.push(['accessibility-id', `~${contentDesc}`]);\n }\n\n // 3. Text (visible text)\n const text = attrs.text;\n if (isValidValue(text) && text.length < 100 && isAttributeUnique(sourceXML, 'text', text)) {\n results.push(['text', `android=new UiSelector().text(\"${escapeText(text)}\")`]);\n }\n } else {\n // iOS simple locators\n\n // 1. Accessibility ID (name attribute)\n const name = attrs.name;\n if (isValidValue(name) && isAttributeUnique(sourceXML, 'name', name)) {\n results.push(['accessibility-id', `~${name}`]);\n }\n\n // 2. Label (visible text, often same as name)\n const label = attrs.label;\n if (isValidValue(label) && label !== name && isAttributeUnique(sourceXML, 'label', label)) {\n results.push(['predicate-string', `-ios predicate string:label == \"${escapeText(label)}\"`]);\n }\n\n // 3. Value\n const value = attrs.value;\n if (isValidValue(value) && isAttributeUnique(sourceXML, 'value', value)) {\n results.push(['predicate-string', `-ios predicate string:value == \"${escapeText(value)}\"`]);\n }\n }\n\n return results;\n}\n\n/**\n * Build Android UiAutomator selector with multiple attributes\n */\nfunction buildUiAutomatorSelector(element: JSONElement): string | null {\n const attrs = element.attributes;\n const parts: string[] = [];\n\n // Build selector with available attributes\n if (isValidValue(attrs['resource-id'])) {\n parts.push(`resourceId(\"${attrs['resource-id']}\")`);\n }\n if (isValidValue(attrs.text) && attrs.text!.length < 100) {\n parts.push(`text(\"${escapeText(attrs.text!)}\")`);\n }\n if (isValidValue(attrs['content-desc'])) {\n parts.push(`description(\"${attrs['content-desc']}\")`);\n }\n if (isValidValue(attrs.class)) {\n parts.push(`className(\"${attrs.class}\")`);\n }\n\n if (parts.length === 0) return null;\n\n return `android=new UiSelector().${parts.join('.')}`;\n}\n\n/**\n * Build iOS predicate string with multiple conditions\n */\nfunction buildPredicateString(element: JSONElement): string | null {\n const attrs = element.attributes;\n const conditions: string[] = [];\n\n if (isValidValue(attrs.name)) {\n conditions.push(`name == \"${escapeText(attrs.name!)}\"`);\n }\n if (isValidValue(attrs.label)) {\n conditions.push(`label == \"${escapeText(attrs.label!)}\"`);\n }\n if (isValidValue(attrs.value)) {\n conditions.push(`value == \"${escapeText(attrs.value!)}\"`);\n }\n if (attrs.visible === 'true') {\n conditions.push('visible == 1');\n }\n if (attrs.enabled === 'true') {\n conditions.push('enabled == 1');\n }\n\n if (conditions.length === 0) return null;\n\n // Use AND for multiple conditions\n return `-ios predicate string:${conditions.join(' AND ')}`;\n}\n\n/**\n * Build iOS class chain selector\n */\nfunction buildClassChain(element: JSONElement): string | null {\n const attrs = element.attributes;\n const tagName = element.tagName;\n\n // Simple class chain with type\n if (!tagName.startsWith('XCUI')) return null;\n\n let selector = `**/${tagName}`;\n\n // Add label predicate if available\n if (isValidValue(attrs.label)) {\n selector += `[\\`label == \"${escapeText(attrs.label!)}\"\\`]`;\n } else if (isValidValue(attrs.name)) {\n selector += `[\\`name == \"${escapeText(attrs.name!)}\"\\`]`;\n }\n\n return `-ios class chain:${selector}`;\n}\n\n/**\n * Build XPath for element with unique identification\n */\nfunction buildXPath(element: JSONElement, sourceXML: string, isAndroid: boolean): string | null {\n const attrs = element.attributes;\n const tagName = element.tagName;\n const conditions: string[] = [];\n\n if (isAndroid) {\n // Android XPath attributes\n if (isValidValue(attrs['resource-id'])) {\n conditions.push(`@resource-id=\"${attrs['resource-id']}\"`);\n }\n if (isValidValue(attrs['content-desc'])) {\n conditions.push(`@content-desc=\"${attrs['content-desc']}\"`);\n }\n if (isValidValue(attrs.text) && attrs.text!.length < 100) {\n conditions.push(`@text=\"${escapeText(attrs.text!)}\"`);\n }\n } else {\n // iOS XPath attributes\n if (isValidValue(attrs.name)) {\n conditions.push(`@name=\"${attrs.name}\"`);\n }\n if (isValidValue(attrs.label)) {\n conditions.push(`@label=\"${attrs.label}\"`);\n }\n if (isValidValue(attrs.value)) {\n conditions.push(`@value=\"${attrs.value}\"`);\n }\n }\n\n // Build XPath\n if (conditions.length === 0) {\n // Fallback: just the tag\n return `//${tagName}`;\n }\n\n // Combine conditions with 'and'\n return `//${tagName}[${conditions.join(' and ')}]`;\n}\n\n/**\n * Get complex locators (combinations, XPath, etc.)\n */\nfunction getComplexSuggestedLocators(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): [LocatorStrategy, string][] {\n const results: [LocatorStrategy, string][] = [];\n const isAndroid = automationName.toLowerCase().includes('uiautomator');\n\n if (isAndroid) {\n // Android complex locators\n\n // UiAutomator with multiple attributes\n const uiAutomator = buildUiAutomatorSelector(element);\n if (uiAutomator) {\n results.push(['uiautomator', uiAutomator]);\n }\n\n // XPath\n const xpath = buildXPath(element, sourceXML, true);\n if (xpath) {\n results.push(['xpath', xpath]);\n }\n\n // Class name (least specific)\n if (isValidValue(element.attributes.class)) {\n results.push([\n 'class-name',\n `android=new UiSelector().className(\"${element.attributes.class}\")`,\n ]);\n }\n } else {\n // iOS complex locators\n\n // Predicate string with multiple conditions\n const predicate = buildPredicateString(element);\n if (predicate) {\n results.push(['predicate-string', predicate]);\n }\n\n // Class chain\n const classChain = buildClassChain(element);\n if (classChain) {\n results.push(['class-chain', classChain]);\n }\n\n // XPath\n const xpath = buildXPath(element, sourceXML, false);\n if (xpath) {\n results.push(['xpath', xpath]);\n }\n\n // Class name (least specific)\n const type = element.tagName;\n if (type.startsWith('XCUIElementType')) {\n results.push(['class-name', `-ios class chain:**/${type}`]);\n }\n }\n\n return results;\n}\n\n/**\n * Get all suggested locators for an element\n * Returns array of [strategy, value] tuples ordered by priority\n *\n * Priority order:\n * Android: id > accessibility-id > text > xpath > uiautomator > class-name\n * iOS: accessibility-id > predicate-string > class-chain > xpath > class-name\n */\nexport function getSuggestedLocators(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): [LocatorStrategy, string][] {\n // Get simple (single attribute) locators first\n const simpleLocators = getSimpleSuggestedLocators(element, sourceXML, isNative, automationName);\n\n // Get complex (combination) locators\n const complexLocators = getComplexSuggestedLocators(element, sourceXML, isNative, automationName);\n\n // Combine, removing duplicates (keep first occurrence)\n const seen = new Set<string>();\n const results: [LocatorStrategy, string][] = [];\n\n for (const locator of [...simpleLocators, ...complexLocators]) {\n if (!seen.has(locator[1])) {\n seen.add(locator[1]);\n results.push(locator);\n }\n }\n\n return results;\n}\n\n/**\n * Get the best (first priority) locator for an element\n */\nexport function getBestLocator(\n element: JSONElement,\n sourceXML: string,\n isNative: boolean,\n automationName: string,\n): string | null {\n const locators = getSuggestedLocators(element, sourceXML, isNative, automationName);\n return locators.length > 0 ? locators[0][1] : null;\n}\n\n/**\n * Convert locator array to object format\n */\nexport function locatorsToObject(locators: [LocatorStrategy, string][]): Record<string, string> {\n const result: Record<string, string> = {};\n for (const [strategy, value] of locators) {\n // Use first locator for each strategy\n if (!result[strategy]) {\n result[strategy] = value;\n }\n }\n return result;\n}\n","/**\n * Main orchestrator for generating locators from page source\n *\n * Based on: https://github.com/appium/appium-mcp/blob/main/src/locators/generate-all-locators.ts\n */\n\nimport type { LocatorStrategy } from './locator-generation';\nimport { getSuggestedLocators, locatorsToObject } from './locator-generation';\nimport type { JSONElement } from './source-parsing';\nimport { parseAndroidBounds, parseIOSBounds, xmlToJSON } from './source-parsing';\nimport type { FilterOptions } from './element-filter';\nimport { hasMeaningfulContent, isLayoutContainer, shouldIncludeElement } from './element-filter';\n\nexport interface ElementWithLocators {\n tagName: string;\n locators: Record<string, string>;\n text: string;\n contentDesc: string;\n resourceId: string;\n accessibilityId: string;\n label: string;\n value: string;\n className: string;\n clickable: boolean;\n enabled: boolean;\n displayed: boolean;\n bounds: { x: number; y: number; width: number; height: number };\n isInViewport: boolean;\n}\n\n/**\n * Processing context - carries all shared state through the processing pipeline\n */\ninterface ProcessingContext {\n sourceXML: string;\n platform: 'android' | 'ios';\n automationName: string;\n isNative: boolean;\n viewportSize: { width: number; height: number };\n filters: FilterOptions;\n results: ElementWithLocators[];\n}\n\n/**\n * Options for generating element locators\n */\nexport interface GenerateLocatorsOptions {\n platform: 'android' | 'ios';\n viewportSize?: { width: number; height: number };\n filters?: FilterOptions;\n isNative?: boolean;\n}\n\n/**\n * Parse element bounds based on platform\n */\nfunction parseBounds(\n element: JSONElement,\n platform: 'android' | 'ios',\n): { x: number; y: number; width: number; height: number } {\n return platform === 'android'\n ? parseAndroidBounds(element.attributes.bounds || '')\n : parseIOSBounds(element.attributes);\n}\n\n/**\n * Check if bounds are within viewport\n */\nfunction isWithinViewport(\n bounds: { x: number; y: number; width: number; height: number },\n viewport: { width: number; height: number },\n): boolean {\n return (\n bounds.x >= 0 &&\n bounds.y >= 0 &&\n bounds.width > 0 &&\n bounds.height > 0 &&\n bounds.x + bounds.width <= viewport.width &&\n bounds.y + bounds.height <= viewport.height\n );\n}\n\n/**\n * Transform JSONElement to ElementWithLocators\n */\nfunction transformElement(element: JSONElement, locators: [LocatorStrategy, string][], ctx: ProcessingContext): ElementWithLocators {\n const attrs = element.attributes;\n const bounds = parseBounds(element, ctx.platform);\n\n return {\n tagName: element.tagName,\n locators: locatorsToObject(locators),\n text: attrs.text || attrs.label || '',\n contentDesc: attrs['content-desc'] || '',\n resourceId: attrs['resource-id'] || '',\n accessibilityId: attrs.name || attrs['content-desc'] || '',\n label: attrs.label || '',\n value: attrs.value || '',\n className: attrs.class || element.tagName,\n clickable: attrs.clickable === 'true' || attrs.accessible === 'true' || attrs['long-clickable'] === 'true',\n enabled: attrs.enabled !== 'false',\n displayed: ctx.platform === 'android' ? attrs.displayed !== 'false' : attrs.visible !== 'false',\n bounds,\n isInViewport: isWithinViewport(bounds, ctx.viewportSize),\n };\n}\n\n/**\n * Check if element should be processed (passes filters or has meaningful content)\n */\nfunction shouldProcess(element: JSONElement, ctx: ProcessingContext): boolean {\n if (shouldIncludeElement(element, ctx.filters, ctx.isNative, ctx.automationName)) {\n return true;\n }\n // Keep layout containers that have meaningful content\n return isLayoutContainer(element, ctx.platform) && hasMeaningfulContent(element, ctx.platform);\n}\n\n/**\n * Process a single element and add to results if valid\n */\nfunction processElement(element: JSONElement, ctx: ProcessingContext): void {\n if (!shouldProcess(element, ctx)) return;\n\n try {\n const locators = getSuggestedLocators(element, ctx.sourceXML, ctx.isNative, ctx.automationName);\n if (locators.length === 0) return;\n\n const transformed = transformElement(element, locators, ctx);\n if (Object.keys(transformed.locators).length === 0) return;\n\n ctx.results.push(transformed);\n } catch (error) {\n console.error(`[processElement] Error at path ${element.path}:`, error);\n }\n}\n\n/**\n * Recursively traverse and process element tree\n */\nfunction traverseTree(element: JSONElement | null, ctx: ProcessingContext): void {\n if (!element) return;\n\n processElement(element, ctx);\n\n for (const child of element.children || []) {\n traverseTree(child, ctx);\n }\n}\n\n/**\n * Generate locators for all elements from page source XML\n */\nexport function generateAllElementLocators(\n sourceXML: string,\n options: GenerateLocatorsOptions,\n): ElementWithLocators[] {\n const sourceJSON = xmlToJSON(sourceXML);\n if (!sourceJSON) {\n console.error('[generateAllElementLocators] Failed to parse page source XML');\n return [];\n }\n\n const ctx: ProcessingContext = {\n sourceXML,\n platform: options.platform,\n automationName: options.platform === 'android' ? 'uiautomator2' : 'xcuitest',\n isNative: options.isNative ?? true,\n viewportSize: options.viewportSize ?? { width: 9999, height: 9999 },\n filters: options.filters ?? {},\n results: [],\n };\n\n traverseTree(sourceJSON, ctx);\n return ctx.results;\n}\n","/**\n * Mobile element detection utilities for iOS and Android\n *\n * Uses page source parsing for optimal performance (2 HTTP calls vs 600+ for 50 elements)\n */\n\nimport type { ElementWithLocators, FilterOptions, LocatorStrategy } from '../locators';\nimport { generateAllElementLocators, getDefaultFilters } from '../locators';\n\n/**\n * Element info returned by getMobileVisibleElements\n * Uses uniform fields (all elements have same keys) to enable TOON tabular format\n */\nexport interface MobileElementInfo {\n selector: string;\n tagName: string;\n isInViewport: boolean;\n text: string;\n resourceId: string;\n accessibilityId: string;\n isEnabled: boolean;\n alternativeSelectors: string[];\n // Only present when includeBounds=true\n bounds?: { x: number; y: number; width: number; height: number };\n}\n\n/**\n * Options for getMobileVisibleElements\n */\nexport interface GetMobileElementsOptions {\n includeContainers?: boolean;\n includeBounds?: boolean;\n filterOptions?: FilterOptions;\n}\n\n/**\n * Locator strategy priority order for selecting best selector\n * Earlier = higher priority\n */\nconst LOCATOR_PRIORITY: LocatorStrategy[] = [\n 'accessibility-id', // Most stable, cross-platform\n 'id', // Android resource-id\n 'text', // Text-based (can be fragile but readable)\n 'predicate-string', // iOS predicate\n 'class-chain', // iOS class chain\n 'uiautomator', // Android UiAutomator compound\n 'xpath', // XPath (last resort, brittle)\n // 'class-name' intentionally excluded - too generic\n];\n\n/**\n * Select best locators from available strategies\n * Returns [primarySelector, ...alternativeSelectors]\n */\nfunction selectBestLocators(locators: Record<string, string>): string[] {\n const selected: string[] = [];\n\n // Find primary selector based on priority\n for (const strategy of LOCATOR_PRIORITY) {\n if (locators[strategy]) {\n selected.push(locators[strategy]);\n break;\n }\n }\n\n // Add one alternative if available (different strategy)\n for (const strategy of LOCATOR_PRIORITY) {\n if (locators[strategy] && !selected.includes(locators[strategy])) {\n selected.push(locators[strategy]);\n break;\n }\n }\n\n return selected;\n}\n\n/**\n * Convert ElementWithLocators to MobileElementInfo\n * Uses uniform fields (all elements have same keys) to enable CSV tabular format\n */\nfunction toMobileElementInfo(element: ElementWithLocators, includeBounds: boolean): MobileElementInfo {\n const selectedLocators = selectBestLocators(element.locators);\n\n // Use contentDesc for accessibilityId on Android, or name on iOS\n const accessId = element.accessibilityId || element.contentDesc;\n\n // Build object with ALL fields for uniform schema (enables CSV tabular format)\n // Empty string '' used for missing values to keep schema consistent\n const info: MobileElementInfo = {\n selector: selectedLocators[0] || '',\n tagName: element.tagName,\n isInViewport: element.isInViewport,\n text: element.text || '',\n resourceId: element.resourceId || '',\n accessibilityId: accessId || '',\n isEnabled: element.enabled !== false,\n alternativeSelectors: selectedLocators.length > 1 ? selectedLocators.slice(1) : [],\n };\n\n // Only include bounds if explicitly requested (adds 4 extra columns)\n if (includeBounds) {\n info.bounds = element.bounds;\n }\n\n return info;\n}\n\n/**\n * Get viewport size from browser\n */\nasync function getViewportSize(browser: WebdriverIO.Browser): Promise<{ width: number; height: number }> {\n try {\n const size = await browser.getWindowSize();\n return { width: size.width, height: size.height };\n } catch {\n return { width: 9999, height: 9999 };\n }\n}\n\n/**\n * Get all visible elements from a mobile app\n *\n * Performance: 2 HTTP calls (getWindowSize + getPageSource) vs 12+ per element with legacy approach\n */\nexport async function getMobileVisibleElements(\n browser: WebdriverIO.Browser,\n platform: 'ios' | 'android',\n options: GetMobileElementsOptions = {},\n): Promise<MobileElementInfo[]> {\n const { includeContainers = false, includeBounds = false, filterOptions } = options;\n\n const viewportSize = await getViewportSize(browser);\n const pageSource = await browser.getPageSource();\n\n const filters: FilterOptions = {\n ...getDefaultFilters(platform, includeContainers),\n ...filterOptions,\n };\n\n const elements = generateAllElementLocators(pageSource, {\n platform,\n viewportSize,\n filters,\n });\n\n return elements.map((el) => toMobileElementInfo(el, includeBounds));\n}\n","import { getBrowser } from './browser.tool';\nimport getInteractableElements from '../scripts/get-interactable-browser-elements';\nimport { getMobileVisibleElements } from '../scripts/get-visible-mobile-elements';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\nimport { encode } from '@toon-format/toon';\nimport { z } from 'zod';\n\n/**\n * Tool definition for get_visible_elements\n */\nexport const getVisibleElementsToolDefinition: ToolDefinition = {\n name: 'get_visible_elements',\n description: 'get a list of visible (in viewport & displayed) interactable elements on the page (buttons, links, inputs). Use elementType=\"visual\" for images/SVGs. Must prefer this to take_screenshot for interactions',\n inputSchema: {\n inViewportOnly: z\n .boolean()\n .optional()\n .describe(\n 'Only return elements within the visible viewport. Default: true. Set to false to get ALL elements on the page.',\n ),\n includeContainers: z\n .boolean()\n .optional()\n .describe(\n 'Include layout containers (ViewGroup, FrameLayout, ScrollView, etc). Default: false. Set to true to see all elements including layouts.',\n ),\n includeBounds: z\n .boolean()\n .optional()\n .describe(\n 'Include element bounds/coordinates (x, y, width, height). Default: false. Set to true for coordinate-based interactions or layout debugging.',\n ),\n elementType: z\n .enum(['interactable', 'visual', 'all'])\n .optional()\n .describe(\n 'Type of elements to return: \"interactable\" (default) for buttons/links/inputs, \"visual\" for images/SVGs, \"all\" for both.',\n ),\n limit: z\n .number()\n .optional()\n .describe('Maximum number of elements to return. Default: 0 (unlimited).'),\n offset: z\n .number()\n .optional()\n .describe('Number of elements to skip (for pagination). Default: 0.'),\n },\n};\n\n/**\n * Get visible elements on the current screen\n * Supports both web browsers and mobile apps (iOS/Android)\n */\nexport const getVisibleElementsTool: ToolCallback = async (args: {\n inViewportOnly?: boolean;\n includeContainers?: boolean;\n includeBounds?: boolean;\n elementType?: 'interactable' | 'visual' | 'all';\n limit?: number;\n offset?: number;\n}) => {\n try {\n const browser = getBrowser();\n const {\n inViewportOnly = true,\n includeContainers = false,\n includeBounds = false,\n elementType = 'interactable',\n limit = 0,\n offset = 0,\n } = args || {};\n\n let elements: { isInViewport?: boolean }[];\n\n if (browser.isAndroid || browser.isIOS) {\n const platform = browser.isAndroid ? 'android' : 'ios';\n elements = await getMobileVisibleElements(browser, platform, { includeContainers, includeBounds });\n } else {\n // Keep uniform fields (no stripping) to enable CSV tabular format\n elements = await browser.execute(getInteractableElements, elementType);\n }\n\n if (inViewportOnly) {\n elements = elements.filter((el) => el.isInViewport !== false);\n }\n\n const total = elements.length;\n\n // Apply pagination\n if (offset > 0) {\n elements = elements.slice(offset);\n }\n if (limit > 0) {\n elements = elements.slice(0, limit);\n }\n\n const result = {\n total,\n showing: elements.length,\n hasMore: offset + elements.length < total,\n elements,\n };\n\n // TOON tabular format with post-processing: replace \"\" with bare commas for efficiency\n const toon = encode(result).replace(/,\"\"/g, ',').replace(/\"\",/g, ',');\n return {\n content: [{ type: 'text', text: toon }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting visible elements: ${e}` }],\n };\n }\n};","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { ToolDefinition } from '../types/tool';\nimport sharp from 'sharp';\n\nconst MAX_DIMENSION = 2000;\nconst MAX_FILE_SIZE_BYTES = 1024 * 1024; // 1MB\n\nexport const takeScreenshotToolDefinition: ToolDefinition = {\n name: 'take_screenshot',\n description: 'captures a screenshot of the current page',\n inputSchema: {\n outputPath: z.string().optional().describe('Optional path where to save the screenshot. If not provided, returns base64 data.'),\n },\n};\n\nasync function processScreenshot(screenshotBase64: string): Promise<{ data: Buffer; mimeType: string }> {\n const inputBuffer = Buffer.from(screenshotBase64, 'base64');\n let image = sharp(inputBuffer);\n const metadata = await image.metadata();\n\n // Resize if any dimension exceeds MAX_DIMENSION\n const width = metadata.width ?? 0;\n const height = metadata.height ?? 0;\n\n if (width > MAX_DIMENSION || height > MAX_DIMENSION) {\n const resizeOptions = width > height\n ? { width: MAX_DIMENSION }\n : { height: MAX_DIMENSION };\n image = image.resize(resizeOptions);\n }\n\n // Try PNG with maximum compression first\n let outputBuffer = await image.png({ compressionLevel: 9 }).toBuffer();\n\n // If still over 1MB, convert to JPEG with progressive quality reduction\n if (outputBuffer.length > MAX_FILE_SIZE_BYTES) {\n let quality = 90;\n while (quality >= 10 && outputBuffer.length > MAX_FILE_SIZE_BYTES) {\n outputBuffer = await image.jpeg({ quality, mozjpeg: true }).toBuffer();\n quality -= 10;\n }\n return { data: outputBuffer, mimeType: 'image/jpeg' };\n }\n\n return { data: outputBuffer, mimeType: 'image/png' };\n}\n\nexport const takeScreenshotTool: ToolCallback = async ({ outputPath }: { outputPath?: string }) => {\n try {\n const browser = getBrowser();\n const screenshot = await browser.takeScreenshot();\n const { data, mimeType } = await processScreenshot(screenshot);\n\n if (outputPath) {\n const fs = await import('node:fs');\n await fs.promises.writeFile(outputPath, data);\n const sizeKB = (data.length / 1024).toFixed(1);\n return {\n content: [{ type: 'text', text: `Screenshot saved to ${outputPath} (${sizeKB}KB, ${mimeType})` }],\n };\n }\n\n const sizeKB = (data.length / 1024).toFixed(1);\n return {\n content: [\n { type: 'text', text: `Screenshot captured (${sizeKB}KB, ${mimeType}):` },\n { type: 'image', data: data.toString('base64'), mimeType },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error taking screenshot: ${(e as Error).message}` }],\n };\n }\n};","import { getBrowser } from './browser.tool';\nimport { z } from 'zod';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { Cookie } from '@wdio/protocols';\nimport type { ToolDefinition } from '../types/tool';\n\n// Tool definitions\nexport const getCookiesToolDefinition: ToolDefinition = {\n name: 'get_cookies',\n description: 'gets all cookies or a specific cookie by name',\n inputSchema: {\n name: z.string().optional().describe('Optional cookie name to retrieve a specific cookie. If not provided, returns all cookies'),\n },\n};\n\nexport const getCookiesTool: ToolCallback = async ({ name}: { name?: string }): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n if (name) {\n // Get specific cookie by name\n const cookie = await browser.getCookies([name]);\n if (cookie.length === 0) {\n return {\n content: [{ type: 'text', text: `Cookie \"${name}\" not found` }],\n };\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(cookie[0], null, 2) }],\n };\n }\n // Get all cookies\n const cookies = await browser.getCookies();\n if (cookies.length === 0) {\n return {\n content: [{ type: 'text', text: 'No cookies found' }],\n };\n }\n return {\n content: [{ type: 'text', text: JSON.stringify(cookies, null, 2) }],\n };\n\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting cookies: ${e}` }],\n };\n }\n};\n\n// Set a cookie\nexport const setCookieToolDefinition: ToolDefinition = {\n name: 'set_cookie',\n description: 'sets a cookie with specified name, value, and optional attributes',\n inputSchema: {\n name: z.string().describe('Cookie name'),\n value: z.string().describe('Cookie value'),\n domain: z.string().optional().describe('Cookie domain (defaults to current domain)'),\n path: z.string().optional().describe('Cookie path (defaults to \"/\")'),\n expiry: z.number().optional().describe('Expiry date as Unix timestamp in seconds'),\n httpOnly: z.boolean().optional().describe('HttpOnly flag'),\n secure: z.boolean().optional().describe('Secure flag'),\n sameSite: z.enum(['strict', 'lax', 'none']).optional().describe('SameSite attribute'),\n },\n};\n\nexport const setCookieTool: ToolCallback = async ({\n name,\n value,\n domain,\n path = '/',\n expiry,\n httpOnly,\n secure,\n sameSite,\n}: Cookie): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const cookie: Cookie = { name, value, path, domain, expiry, httpOnly, secure, sameSite };\n\n await browser.setCookies(cookie);\n\n return {\n content: [{ type: 'text', text: `Cookie \"${name}\" set successfully` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error setting cookie: ${e}` }],\n };\n }\n};\n\n// Delete cookies\nexport const deleteCookiesToolDefinition: ToolDefinition = {\n name: 'delete_cookies',\n description: 'deletes all cookies or a specific cookie by name',\n inputSchema: {\n name: z.string().optional().describe('Optional cookie name to delete a specific cookie. If not provided, deletes all cookies'),\n },\n};\n\nexport const deleteCookiesTool: ToolCallback = async ({ name}: { name?: string }): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n if (name) {\n // Delete specific cookie by name\n await browser.deleteCookies([name]);\n return {\n content: [{ type: 'text', text: `Cookie \"${name}\" deleted successfully` }],\n };\n }\n // Delete all cookies\n await browser.deleteCookies();\n return {\n content: [{ type: 'text', text: 'All cookies deleted successfully' }],\n };\n\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error deleting cookies: ${e}` }],\n };\n }\n};\n","import { getBrowser } from './browser.tool';\nimport type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { encode } from '@toon-format/toon';\nimport { z } from 'zod';\n\n/**\n * Tool definition for get_accessibility\n */\nexport const getAccessibilityToolDefinition: ToolDefinition = {\n name: 'get_accessibility',\n description: 'gets accessibility tree snapshot with semantic information about page elements (roles, names, states). Browser-only - use when get_visible_elements does not return expected elements.',\n inputSchema: {\n limit: z.number().optional()\n .describe('Maximum number of nodes to return. Default: 100. Use 0 for unlimited.'),\n offset: z.number().optional()\n .describe('Number of nodes to skip (for pagination). Default: 0.'),\n roles: z.array(z.string()).optional()\n .describe('Filter to specific roles (e.g., [\"button\", \"link\", \"textbox\"]). Default: all roles.'),\n namedOnly: z.boolean().optional()\n .describe('Only return nodes with a name/label. Default: true. Filters out anonymous containers.'),\n },\n};\n\n/**\n * Flatten a hierarchical accessibility tree into a flat list\n * Uses uniform fields (all nodes have same keys) to enable tabular format\n * @param node - The accessibility node\n * @param result - Accumulator array\n */\nfunction flattenAccessibilityTree(node: any, result: any[] = []): any[] {\n if (!node) return result;\n\n // Add current node (excluding root WebArea unless it has meaningful content)\n if (node.role !== 'WebArea' || node.name) {\n // Build object with ALL fields for uniform schema (enables tabular format)\n // Empty string '' used for missing values to keep schema consistent\n const entry: Record<string, any> = {\n // Primary identifiers (most useful)\n role: node.role || '',\n name: node.name || '',\n value: node.value ?? '',\n description: node.description || '',\n // Boolean states (empty string = not applicable/false)\n disabled: node.disabled ? 'true' : '',\n focused: node.focused ? 'true' : '',\n selected: node.selected ? 'true' : '',\n checked: node.checked === true ? 'true' : node.checked === false ? 'false' : node.checked === 'mixed' ? 'mixed' : '',\n expanded: node.expanded === true ? 'true' : node.expanded === false ? 'false' : '',\n pressed: node.pressed === true ? 'true' : node.pressed === false ? 'false' : node.pressed === 'mixed' ? 'mixed' : '',\n readonly: node.readonly ? 'true' : '',\n required: node.required ? 'true' : '',\n // Less common properties\n level: node.level ?? '',\n valuemin: node.valuemin ?? '',\n valuemax: node.valuemax ?? '',\n autocomplete: node.autocomplete || '',\n haspopup: node.haspopup || '',\n invalid: node.invalid ? 'true' : '',\n modal: node.modal ? 'true' : '',\n multiline: node.multiline ? 'true' : '',\n multiselectable: node.multiselectable ? 'true' : '',\n orientation: node.orientation || '',\n keyshortcuts: node.keyshortcuts || '',\n roledescription: node.roledescription || '',\n valuetext: node.valuetext || '',\n };\n\n result.push(entry);\n }\n\n // Recursively process children\n if (node.children && Array.isArray(node.children)) {\n for (const child of node.children) {\n flattenAccessibilityTree(child, result);\n }\n }\n\n return result;\n}\n\nexport const getAccessibilityTreeTool: ToolCallback = async (args: {\n limit?: number;\n offset?: number;\n roles?: string[];\n namedOnly?: boolean;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n // Check if this is a mobile session - accessibility tree is browser-only\n if (browser.isAndroid || browser.isIOS) {\n return {\n content: [{\n type: 'text',\n text: 'Error: get_accessibility is browser-only. For mobile apps, use get_visible_elements instead.',\n }],\n };\n }\n\n const { limit = 100, offset = 0, roles, namedOnly = true } = args || {};\n\n // Get Puppeteer instance for native accessibility API\n const puppeteer = await browser.getPuppeteer();\n const pages = await puppeteer.pages();\n\n if (pages.length === 0) {\n return {\n content: [{ type: 'text', text: 'No active pages found' }],\n };\n }\n\n const page = pages[0];\n\n // Get accessibility snapshot with interestingOnly filter\n const snapshot = await page.accessibility.snapshot({\n interestingOnly: true, // Filter to only interesting/semantic nodes\n });\n\n if (!snapshot) {\n return {\n content: [{ type: 'text', text: 'No accessibility tree available' }],\n };\n }\n\n // Flatten the hierarchical tree into a flat list\n let nodes = flattenAccessibilityTree(snapshot);\n\n // Filter to named nodes only (removes anonymous containers, StaticText duplicates)\n if (namedOnly) {\n nodes = nodes.filter(n => n.name && n.name.trim() !== '');\n }\n\n // Filter to specific roles if provided\n if (roles && roles.length > 0) {\n const roleSet = new Set(roles.map(r => r.toLowerCase()));\n nodes = nodes.filter(n => n.role && roleSet.has(n.role.toLowerCase()));\n }\n\n const total = nodes.length;\n\n // Apply pagination\n if (offset > 0) {\n nodes = nodes.slice(offset);\n }\n if (limit > 0) {\n nodes = nodes.slice(0, limit);\n }\n\n const result = {\n total,\n showing: nodes.length,\n hasMore: offset + nodes.length < total,\n nodes,\n };\n\n // Post-process: replace \"\" with bare commas for efficiency\n const toon = encode(result)\n .replace(/,\"\"/g, ',')\n .replace(/\"\",/g, ',');\n\n return {\n content: [{ type: 'text', text: toon }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting accessibility tree: ${e}` }],\n };\n }\n};","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Tap Tool\nexport const tapElementToolDefinition: ToolDefinition = {\n name: 'tap_element',\n description: 'taps an element by selector or screen coordinates (mobile)',\n inputSchema: {\n selector: z\n .string()\n .optional()\n .describe('Element selector (CSS, XPath, accessibility ID, or UiAutomator)'),\n x: z.number().optional().describe('X coordinate for screen tap (if no selector provided)'),\n y: z.number().optional().describe('Y coordinate for screen tap (if no selector provided)'),\n },\n};\n\nexport const tapElementTool: ToolCallback = async (args: {\n selector?: string;\n x?: number;\n y?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { selector, x, y } = args;\n\n if (selector) {\n const element = await browser.$(selector);\n await element.tap();\n return {\n content: [{ type: 'text', text: `Tapped element: ${selector}` }],\n };\n } else if (x !== undefined && y !== undefined) {\n await browser.tap({ x, y });\n return {\n content: [{ type: 'text', text: `Tapped at coordinates: (${x}, ${y})` }],\n };\n }\n\n return {\n content: [{ type: 'text', text: 'Error: Must provide either selector or x,y coordinates' }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error tapping: ${e}` }],\n };\n }\n};\n\n// Swipe Tool\nexport const swipeToolDefinition: ToolDefinition = {\n name: 'swipe',\n description: 'performs a swipe gesture in specified direction (mobile)',\n inputSchema: {\n direction: z.enum(['up', 'down', 'left', 'right']).describe('Swipe direction'),\n duration: z\n .number()\n .min(100)\n .max(5000)\n .optional()\n .describe('Swipe duration in milliseconds (default: 500)'),\n percent: z\n .number()\n .min(0)\n .max(1)\n .optional()\n .describe('Percentage of screen to swipe (0-1, default: 0.5 for up/down, 0.95 for left/right)'),\n },\n};\n\n// Map content direction to finger direction (inverted)\n// \"swipe left\" = content moves left = finger moves right\nconst contentToFingerDirection: Record<string, 'up' | 'down' | 'left' | 'right'> = {\n up: 'down',\n down: 'up',\n left: 'right',\n right: 'left',\n};\n\nexport const swipeTool: ToolCallback = async (args: {\n direction: 'up' | 'down' | 'left' | 'right';\n duration?: number;\n percent?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { direction, duration, percent } = args;\n\n // Direction-specific defaults: vertical (up/down) = 0.5, horizontal (left/right) = 0.95\n const isVertical = direction === 'up' || direction === 'down';\n const defaultPercent = isVertical ? 0.5 : 0.95;\n const effectivePercent = percent ?? defaultPercent;\n const effectiveDuration = duration ?? 500;\n\n // Convert content direction to finger direction\n const fingerDirection = contentToFingerDirection[direction];\n await browser.swipe({ direction: fingerDirection, duration: effectiveDuration, percent: effectivePercent });\n\n return {\n content: [{ type: 'text', text: `Swiped ${direction}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error swiping: ${e}` }],\n };\n }\n};\n\n// Drag and Drop Tool\nexport const dragAndDropToolDefinition: ToolDefinition = {\n name: 'drag_and_drop',\n description: 'drags an element to another element or coordinates (mobile)',\n inputSchema: {\n sourceSelector: z.string().describe('Source element selector to drag'),\n targetSelector: z.string().optional().describe('Target element selector to drop onto'),\n x: z.number().optional().describe('Target X offset (if no targetSelector)'),\n y: z.number().optional().describe('Target Y offset (if no targetSelector)'),\n duration: z.number().min(100).max(5000).optional().describe('Drag duration in milliseconds'),\n },\n};\n\nexport const dragAndDropTool: ToolCallback = async (args: {\n sourceSelector: string;\n targetSelector?: string;\n x?: number;\n y?: number;\n duration?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { sourceSelector, targetSelector, x, y, duration } = args;\n\n const sourceElement = await browser.$(sourceSelector);\n\n if (targetSelector) {\n const targetElement = await browser.$(targetSelector);\n await sourceElement.dragAndDrop(targetElement, { duration });\n return {\n content: [{ type: 'text', text: `Dragged ${sourceSelector} to ${targetSelector}` }],\n };\n } else if (x !== undefined && y !== undefined) {\n await sourceElement.dragAndDrop({ x, y }, { duration });\n return {\n content: [{ type: 'text', text: `Dragged ${sourceSelector} by (${x}, ${y})` }],\n };\n }\n\n return {\n content: [{ type: 'text', text: 'Error: Must provide either targetSelector or x,y coordinates' }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error dragging: ${e}` }],\n };\n }\n};","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Get App State Tool\nexport const getAppStateToolDefinition: ToolDefinition = {\n name: 'get_app_state',\n description: 'gets the state of an app (not installed, not running, background, foreground)',\n inputSchema: {\n bundleId: z.string().describe('App bundle ID (e.g., com.example.app)'),\n },\n};\n\nexport const getAppStateTool: ToolCallback = async (args: {\n bundleId: string;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { bundleId } = args;\n\n const appIdentifier = browser.isAndroid\n ? { appId: bundleId }\n : { bundleId: bundleId };\n\n const state: string = await browser.execute('mobile: queryAppState', appIdentifier);\n\n const stateMap: Record<string, string> = {\n 0: 'not installed',\n 1: 'not running',\n 2: 'running in background (suspended)',\n 3: 'running in background',\n 4: 'running in foreground',\n };\n\n return {\n content: [\n {\n type: 'text',\n text: `App state for ${bundleId}: ${stateMap[state] || 'unknown: ' + state}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting app state: ${e}` }],\n };\n }\n};\n\n","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Get Contexts Tool Definition\nexport const getContextsToolDefinition: ToolDefinition = {\n name: 'get_contexts',\n description: 'lists available contexts (NATIVE_APP, WEBVIEW)',\n inputSchema: {},\n};\n\n// Get Current Context Tool Definition\nexport const getCurrentContextToolDefinition: ToolDefinition = {\n name: 'get_current_context',\n description: 'shows the currently active context',\n inputSchema: {},\n};\n\n// Switch Context Tool Definition\nexport const switchContextToolDefinition: ToolDefinition = {\n name: 'switch_context',\n description: 'switches between native and webview contexts',\n inputSchema: {\n context: z\n .string()\n .describe(\n 'Context name to switch to (e.g., \"NATIVE_APP\", \"WEBVIEW_com.example.app\", or use index from get_contexts)',\n ),\n },\n};\n\n// Get Contexts Tool\nexport const getContextsTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const contexts = await browser.getContexts();\n\n return {\n content: [\n {\n type: 'text',\n text: `Available contexts:\\n${contexts.map((ctx, idx) => `${idx + 1}. ${ctx}`).join('\\n')}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting contexts: ${e}` }],\n };\n }\n};\n\n// Get Current Context Tool\nexport const getCurrentContextTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const currentContext = await browser.getContext();\n\n return {\n content: [{ type: 'text', text: `Current context: ${JSON.stringify(currentContext)}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting current context: ${e}` }],\n };\n }\n};\n\nexport const switchContextTool: ToolCallback = async (args: {\n context: string;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { context } = args;\n\n // If context is a number, get the context by index\n let targetContext = context;\n if (/^\\d+$/.test(context)) {\n const contexts = await browser.getContexts();\n const index = parseInt(context, 10) - 1; // Convert to 0-based index\n if (index >= 0 && index < contexts.length) {\n targetContext = contexts[index] as string;\n } else {\n return {\n content: [\n {\n type: 'text',\n text: `Error: Invalid context index ${context}. Available contexts: ${contexts.length}`,\n },\n ],\n };\n }\n }\n\n await browser.switchContext(targetContext);\n\n return {\n content: [{ type: 'text', text: `Switched to context: ${targetContext}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error switching context: ${e}` }],\n };\n }\n};\n","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\n// Tool Definitions for zero-argument tools\nexport const hideKeyboardToolDefinition: ToolDefinition = {\n name: 'hide_keyboard',\n description: 'hides the on-screen keyboard',\n inputSchema: {},\n};\n\nexport const getGeolocationToolDefinition: ToolDefinition = {\n name: 'get_geolocation',\n description: 'gets current device geolocation',\n inputSchema: {},\n};\n\n// Tool Definitions for tools with arguments\nexport const rotateDeviceToolDefinition: ToolDefinition = {\n name: 'rotate_device',\n description: 'rotates device to portrait or landscape orientation',\n inputSchema: {\n orientation: z.enum(['PORTRAIT', 'LANDSCAPE']).describe('Device orientation'),\n },\n};\n\nexport const setGeolocationToolDefinition: ToolDefinition = {\n name: 'set_geolocation',\n description: 'sets device geolocation (latitude, longitude, altitude)',\n inputSchema: {\n latitude: z.number().min(-90).max(90).describe('Latitude coordinate'),\n longitude: z.number().min(-180).max(180).describe('Longitude coordinate'),\n altitude: z.number().optional().describe('Altitude in meters (optional)'),\n },\n};\n\n// Rotate Device Tool\nexport const rotateDeviceTool: ToolCallback = async (args: {\n orientation: 'PORTRAIT' | 'LANDSCAPE';\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { orientation } = args;\n\n await browser.setOrientation(orientation);\n\n return {\n content: [{ type: 'text', text: `Device rotated to: ${orientation}` }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error rotating device: ${e}` }],\n };\n }\n};\n\n// Hide Keyboard Tool\nexport const hideKeyboardTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n await browser.hideKeyboard();\n\n return {\n content: [{ type: 'text', text: 'Keyboard hidden' }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error hiding keyboard: ${e}` }],\n };\n }\n};\n\n// Get Geolocation Tool\nexport const getGeolocationTool: ToolCallback = async (): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n\n const location = await browser.getGeoLocation();\n\n return {\n content: [\n {\n type: 'text',\n text: `Location:\\n Latitude: ${location.latitude}\\n Longitude: ${location.longitude}\\n Altitude: ${location.altitude || 'N/A'}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error getting geolocation: ${e}` }],\n };\n }\n};\n\n// Set Geolocation Tool\nexport const setGeolocationTool: ToolCallback = async (args: {\n latitude: number;\n longitude: number;\n altitude?: number;\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { latitude, longitude, altitude } = args;\n\n await browser.setGeoLocation({ latitude, longitude, altitude });\n\n return {\n content: [\n {\n type: 'text',\n text: `Geolocation set to:\\n Latitude: ${latitude}\\n Longitude: ${longitude}${altitude ? `\\n Altitude: ${altitude}m` : ''}`,\n },\n ],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error setting geolocation: ${e}` }],\n };\n }\n};\n","import type { ToolCallback } from '@modelcontextprotocol/sdk/server/mcp';\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types';\nimport type { ToolDefinition } from '../types/tool';\nimport { z } from 'zod';\nimport { getBrowser } from './browser.tool';\n\nexport const executeScriptToolDefinition: ToolDefinition = {\n name: 'execute_script',\n description: `Executes JavaScript in browser or mobile commands via Appium.\n\n**Browser:** Runs JavaScript in page context. Use 'return' to get values back.\n - Example: execute_script({ script: \"return document.title\" })\n - Example: execute_script({ script: \"return window.scrollY\" })\n - Example: execute_script({ script: \"arguments[0].click()\", args: [\"#myButton\"] })\n\n**Mobile (Appium):** Executes mobile-specific commands using 'mobile: <command>' syntax.\n - Press key (Android): execute_script({ script: \"mobile: pressKey\", args: [{ keycode: 4 }] }) // BACK=4, HOME=3\n - Activate app: execute_script({ script: \"mobile: activateApp\", args: [{ appId: \"com.example\" }] })\n - Terminate app: execute_script({ script: \"mobile: terminateApp\", args: [{ appId: \"com.example\" }] })\n - Deep link: execute_script({ script: \"mobile: deepLink\", args: [{ url: \"myapp://screen\", package: \"com.example\" }] })\n - Shell command (Android): execute_script({ script: \"mobile: shell\", args: [{ command: \"dumpsys\", args: [\"battery\"] }] })`,\n inputSchema: {\n script: z.string().describe('JavaScript code (browser) or mobile command string like \"mobile: pressKey\" (Appium)'),\n args: z.array(z.any()).optional().describe('Arguments to pass to the script. For browser: element selectors or values. For mobile commands: command-specific parameters as objects.'),\n },\n};\n\nexport const executeScriptTool: ToolCallback = async (args: {\n script: string;\n args?: unknown[];\n}): Promise<CallToolResult> => {\n try {\n const browser = getBrowser();\n const { script, args: scriptArgs = [] } = args;\n\n // For browser scripts with selector arguments, resolve them to elements\n const resolvedArgs = await Promise.all(\n scriptArgs.map(async (arg) => {\n // If it's a string that looks like a selector and we're in browser context, try to resolve it\n if (typeof arg === 'string' && !script.startsWith('mobile:')) {\n try {\n const element = await browser.$(arg);\n if (await element.isExisting()) {\n return element;\n }\n } catch {\n // Not a valid selector, pass as-is\n }\n }\n return arg;\n })\n );\n\n const result = await browser.execute(script, ...resolvedArgs);\n\n // Format result for display\n let resultText: string;\n if (result === undefined || result === null) {\n resultText = 'Script executed successfully (no return value)';\n } else if (typeof result === 'object') {\n try {\n resultText = `Result: ${JSON.stringify(result, null, 2)}`;\n } catch {\n resultText = `Result: ${String(result)}`;\n }\n } else {\n resultText = `Result: ${result}`;\n }\n\n return {\n content: [{ type: 'text', text: resultText }],\n };\n } catch (e) {\n return {\n content: [{ type: 'text', text: `Error executing script: ${e}` }],\n };\n }\n};\n","{\n \"name\": \"@wdio/mcp\",\n \"author\": \"Vince Graics\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git://github.com/webdriverio/mcp.git\"\n },\n \"version\": \"2.0.0\",\n \"description\": \"MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)\",\n \"main\": \"./lib/server.js\",\n \"module\": \"./lib/server.js\",\n \"types\": \"./lib/server.d.ts\",\n \"bin\": {\n \"wdio-mcp\": \"lib/server.js\"\n },\n \"license\": \"MIT\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"type\": \"module\",\n \"files\": [\n \"lib\",\n \"README.md\"\n ],\n \"scripts\": {\n \"prebundle\": \"rimraf lib --glob ./*.tgz\",\n \"bundle\": \"tsup && shx chmod +x lib/server.js\",\n \"postbundle\": \"npm pack\",\n \"lint\": \"eslint src/ --fix && tsc --noEmit\",\n \"start\": \"node lib/server.js\",\n \"dev\": \"tsx --watch src/server.ts\",\n \"prepare\": \"husky\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"1.25\",\n \"@toon-format/toon\": \"^2.1.0\",\n \"@wdio/protocols\": \"^9.16.2\",\n \"@xmldom/xmldom\": \"^0.8.11\",\n \"puppeteer-core\": \"^24.35.0\",\n \"sharp\": \"^0.34.5\",\n \"webdriverio\": \"9.23\",\n \"zod\": \"^4.3.5\"\n },\n \"devDependencies\": {\n \"@release-it/conventional-changelog\": \"^10.0.4\",\n \"@types/node\": \"^20.11.0\",\n \"@wdio/eslint\": \"^0.1.3\",\n \"@wdio/types\": \"^9.20.0\",\n \"eslint\": \"^9.39.2\",\n \"husky\": \"^9.1.7\",\n \"release-it\": \"^19.2.3\",\n \"rimraf\": \"^6.1.2\",\n \"shx\": \"^0.4.0\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.21.0\",\n \"typescript\": \"5.9\"\n },\n \"packageManager\": \"pnpm@10.12.4\"\n}\n"],"mappings":"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","names":["z","z","z","defaultTimeout","remote","z","z","remote","state","z","state","z","z","sizeKB","z","encode","z","z","z","z","z","state","z","z","z","z","z","z"]}
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "git://github.com/webdriverio/mcp.git"
7
7
  },
8
- "version": "2.0.0",
8
+ "version": "2.1.0",
9
9
  "description": "MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)",
10
10
  "main": "./lib/server.js",
11
11
  "module": "./lib/server.js",