@wdio/mcp 1.5.0 → 1.6.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
@@ -7,13 +7,21 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
7
7
  // src/tools/browser.tool.ts
8
8
  import { remote } from "webdriverio";
9
9
  import { z } from "zod";
10
- var startBrowserToolArguments = {
11
- headless: z.boolean().optional(),
12
- windowWidth: z.number().min(400).max(3840).optional(),
13
- windowHeight: z.number().min(400).max(2160).optional()
10
+ var startBrowserToolDefinition = {
11
+ name: "start_browser",
12
+ description: "starts a browser session and sets it to the current state",
13
+ inputSchema: {
14
+ headless: z.boolean().optional(),
15
+ windowWidth: z.number().min(400).max(3840).optional(),
16
+ windowHeight: z.number().min(400).max(2160).optional()
17
+ }
14
18
  };
15
- var closeSessionToolArguments = {
16
- detach: z.boolean().optional().describe("If true, disconnect from session without terminating it (preserves app state). Default: false")
19
+ var closeSessionToolDefinition = {
20
+ name: "close_session",
21
+ description: "closes or detaches from the current browser or app session",
22
+ inputSchema: {
23
+ detach: z.boolean().optional().describe("If true, disconnect from session without terminating it (preserves app state). Default: false")
24
+ }
17
25
  };
18
26
  var state = {
19
27
  browsers: /* @__PURE__ */ new Map(),
@@ -95,8 +103,12 @@ var closeSessionTool = async (args = {}) => {
95
103
 
96
104
  // src/tools/navigate.tool.ts
97
105
  import { z as z2 } from "zod";
98
- var navigateToolArguments = {
99
- url: z2.string().nonempty("URL must be provided")
106
+ var navigateToolDefinition = {
107
+ name: "navigate",
108
+ description: "navigates to a URL",
109
+ inputSchema: {
110
+ url: z2.string().min(1).describe("The URL to navigate to")
111
+ }
100
112
  };
101
113
  var navigateTool = async ({ url }) => {
102
114
  try {
@@ -115,10 +127,23 @@ var navigateTool = async ({ url }) => {
115
127
  // src/tools/click.tool.ts
116
128
  import { z as z3 } from "zod";
117
129
  var defaultTimeout = 3e3;
118
- var clickToolArguments = {
119
- selector: z3.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")`),
120
- scrollToView: z3.boolean().optional().describe("Whether to scroll the element into view before clicking").default(true),
121
- timeout: z3.number().optional().describe("Maximum time to wait for element in milliseconds")
130
+ var clickToolDefinition = {
131
+ name: "click_element",
132
+ description: "clicks an element",
133
+ inputSchema: {
134
+ selector: z3.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")`),
135
+ scrollToView: z3.boolean().optional().describe("Whether to scroll the element into view before clicking").default(true),
136
+ timeout: z3.number().optional().describe("Maximum time to wait for element in milliseconds")
137
+ }
138
+ };
139
+ var clickViaTextToolDefinition = {
140
+ name: "click_via_text",
141
+ description: "clicks an element",
142
+ inputSchema: {
143
+ selector: z3.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")`),
144
+ scrollToView: z3.boolean().optional().describe("Whether to scroll the element into view before clicking").default(true),
145
+ timeout: z3.number().optional().describe("Maximum time to wait for element in milliseconds")
146
+ }
122
147
  };
123
148
  var clickAction = async (selector, timeout, scrollToView = true) => {
124
149
  try {
@@ -143,11 +168,15 @@ var clickToolViaText = async ({ text, scrollToView, timeout = defaultTimeout })
143
168
  // src/tools/set-value.tool.ts
144
169
  import { z as z4 } from "zod";
145
170
  var defaultTimeout2 = 3e3;
146
- var setValueToolArguments = {
147
- selector: z4.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
148
- value: z4.string().describe("Text to enter into the element"),
149
- scrollToView: z4.boolean().optional().describe("Whether to scroll the element into view before typing").default(true),
150
- timeout: z4.number().optional().describe("Maximum time to wait for element in milliseconds")
171
+ var setValueToolDefinition = {
172
+ name: "set_value",
173
+ description: "set value to an element, aka typing",
174
+ inputSchema: {
175
+ selector: z4.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
176
+ value: z4.string().describe("Text to enter into the element"),
177
+ scrollToView: z4.boolean().optional().describe("Whether to scroll the element into view before typing").default(true),
178
+ timeout: z4.number().optional().describe("Maximum time to wait for element in milliseconds")
179
+ }
151
180
  };
152
181
  var setValueTool = async ({ selector, value, scrollToView = true, timeout = defaultTimeout2 }) => {
153
182
  try {
@@ -171,9 +200,13 @@ var setValueTool = async ({ selector, value, scrollToView = true, timeout = defa
171
200
  // src/tools/find-element.tool.ts
172
201
  import { z as z5 } from "zod";
173
202
  var defaultTimeout3 = 3e3;
174
- var findElementToolArguments = {
175
- selector: z5.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
176
- timeout: z5.number().optional().describe("Maximum time to wait for element in milliseconds")
203
+ var findElementToolDefinition = {
204
+ name: "find_element",
205
+ description: "finds an element",
206
+ inputSchema: {
207
+ selector: z5.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
208
+ timeout: z5.number().optional().describe("Maximum time to wait for element in milliseconds")
209
+ }
177
210
  };
178
211
  var findElementTool = async ({ selector, timeout = defaultTimeout3 }) => {
179
212
  try {
@@ -192,9 +225,13 @@ var findElementTool = async ({ selector, timeout = defaultTimeout3 }) => {
192
225
  // src/tools/get-element-text.tool.ts
193
226
  import { z as z6 } from "zod";
194
227
  var defaultTimeout4 = 3e3;
195
- var getElementTextToolArguments = {
196
- selector: z6.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
197
- timeout: z6.number().optional().describe("Maximum time to wait for element in milliseconds")
228
+ var getElementTextToolDefinition = {
229
+ name: "get_element_text",
230
+ description: "gets the text content of an element",
231
+ inputSchema: {
232
+ selector: z6.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
233
+ timeout: z6.number().optional().describe("Maximum time to wait for element in milliseconds")
234
+ }
198
235
  };
199
236
  var getElementTextTool = async ({ selector, timeout = defaultTimeout4 }) => {
200
237
  try {
@@ -214,9 +251,13 @@ var getElementTextTool = async ({ selector, timeout = defaultTimeout4 }) => {
214
251
  // src/tools/is-displayed.tool.ts
215
252
  import { z as z7 } from "zod";
216
253
  var defaultTimeout5 = 3e3;
217
- var isDisplayedToolArguments = {
218
- selector: z7.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
219
- timeout: z7.number().optional().describe("Maximum time to wait for element in milliseconds")
254
+ var isDisplayedToolDefinition = {
255
+ name: "is_displayed",
256
+ description: "checks if an element is displayed",
257
+ inputSchema: {
258
+ selector: z7.string().describe(`Value for the selector, in the form of css selector or xpath ("button.my-class" or "//button[@class='my-class']")`),
259
+ timeout: z7.number().optional().describe("Maximum time to wait for element in milliseconds")
260
+ }
220
261
  };
221
262
  var isDisplayedTool = async ({ selector, timeout = defaultTimeout5 }) => {
222
263
  try {
@@ -238,8 +279,12 @@ var isDisplayedTool = async ({ selector, timeout = defaultTimeout5 }) => {
238
279
 
239
280
  // src/tools/scroll-down.tool.ts
240
281
  import { z as z8 } from "zod";
241
- var scrollDownToolArguments = {
242
- pixels: z8.number().optional().default(500)
282
+ var scrollDownToolDefinition = {
283
+ name: "scroll_down",
284
+ description: "scrolls the page down by specified pixels",
285
+ inputSchema: {
286
+ pixels: z8.number().optional().default(500)
287
+ }
243
288
  };
244
289
  var scrollDownTool = async ({ pixels = 500 }) => {
245
290
  try {
@@ -259,8 +304,12 @@ var scrollDownTool = async ({ pixels = 500 }) => {
259
304
 
260
305
  // src/tools/scroll-up.tool.ts
261
306
  import { z as z9 } from "zod";
262
- var scrollUpToolArguments = {
263
- pixels: z9.number().optional().default(500)
307
+ var scrollUpToolDefinition = {
308
+ name: "scroll_up",
309
+ description: "scrolls the page up by specified pixels",
310
+ inputSchema: {
311
+ pixels: z9.number().optional().default(500)
312
+ }
264
313
  };
265
314
  var scrollUpTool = async ({ pixels = 500 }) => {
266
315
  try {
@@ -1049,24 +1098,66 @@ function generateAllElementLocators(sourceXML, options) {
1049
1098
  }
1050
1099
 
1051
1100
  // src/utils/mobile-elements.ts
1052
- function toMobileElementInfo(element) {
1053
- const locatorValues = Object.values(element.locators);
1054
- return {
1055
- selector: locatorValues[0] || "",
1056
- alternativeSelectors: locatorValues.length > 1 ? locatorValues.slice(1, 3) : void 0,
1057
- locators: element.locators,
1058
- isInViewport: element.isInViewport,
1059
- isEnabled: element.enabled,
1060
- bounds: element.bounds,
1061
- tagName: element.tagName || void 0,
1062
- text: element.text || void 0,
1063
- resourceId: element.resourceId || void 0,
1064
- contentDesc: element.contentDesc || void 0,
1065
- accessibilityId: element.accessibilityId || void 0,
1066
- label: element.label || void 0,
1067
- value: element.value || void 0,
1068
- className: element.className || void 0
1101
+ var LOCATOR_PRIORITY = [
1102
+ "accessibility-id",
1103
+ // Most stable, cross-platform
1104
+ "id",
1105
+ // Android resource-id
1106
+ "text",
1107
+ // Text-based (can be fragile but readable)
1108
+ "predicate-string",
1109
+ // iOS predicate
1110
+ "class-chain",
1111
+ // iOS class chain
1112
+ "uiautomator",
1113
+ // Android UiAutomator compound
1114
+ "xpath"
1115
+ // XPath (last resort, brittle)
1116
+ // 'class-name' intentionally excluded - too generic
1117
+ ];
1118
+ function selectBestLocators(locators) {
1119
+ const selected = [];
1120
+ for (const strategy of LOCATOR_PRIORITY) {
1121
+ if (locators[strategy]) {
1122
+ selected.push(locators[strategy]);
1123
+ break;
1124
+ }
1125
+ }
1126
+ for (const strategy of LOCATOR_PRIORITY) {
1127
+ if (locators[strategy] && !selected.includes(locators[strategy])) {
1128
+ selected.push(locators[strategy]);
1129
+ break;
1130
+ }
1131
+ }
1132
+ return selected;
1133
+ }
1134
+ function toMobileElementInfo(element, includeBounds) {
1135
+ const selectedLocators = selectBestLocators(element.locators);
1136
+ const info = {
1137
+ selector: selectedLocators[0] || "",
1138
+ tagName: element.tagName,
1139
+ isInViewport: element.isInViewport
1069
1140
  };
1141
+ if (element.text) {
1142
+ info.text = element.text;
1143
+ }
1144
+ if (element.resourceId) {
1145
+ info.resourceId = element.resourceId;
1146
+ }
1147
+ const accessId = element.accessibilityId || element.contentDesc;
1148
+ if (accessId) {
1149
+ info.accessibilityId = accessId;
1150
+ }
1151
+ if (!element.enabled) {
1152
+ info.isEnabled = false;
1153
+ }
1154
+ if (selectedLocators.length > 1) {
1155
+ info.alternativeSelectors = selectedLocators.slice(1);
1156
+ }
1157
+ if (includeBounds) {
1158
+ info.bounds = element.bounds;
1159
+ }
1160
+ return info;
1070
1161
  }
1071
1162
  async function getViewportSize(browser) {
1072
1163
  try {
@@ -1077,7 +1168,7 @@ async function getViewportSize(browser) {
1077
1168
  }
1078
1169
  }
1079
1170
  async function getMobileVisibleElements(browser, platform, options = {}) {
1080
- const { includeContainers = false, filterOptions } = options;
1171
+ const { includeContainers = false, includeBounds = false, filterOptions } = options;
1081
1172
  const viewportSize = await getViewportSize(browser);
1082
1173
  const pageSource = await browser.getPageSource();
1083
1174
  const filters = {
@@ -1089,7 +1180,7 @@ async function getMobileVisibleElements(browser, platform, options = {}) {
1089
1180
  viewportSize,
1090
1181
  filters
1091
1182
  });
1092
- return elements.map(toMobileElementInfo);
1183
+ return elements.map((el) => toMobileElementInfo(el, includeBounds));
1093
1184
  }
1094
1185
 
1095
1186
  // src/tools/get-visible-elements.tool.ts
@@ -1107,19 +1198,25 @@ function stripUndefinedFromArray(arr) {
1107
1198
  }
1108
1199
 
1109
1200
  // src/tools/get-visible-elements.tool.ts
1110
- var getVisibleElementsToolArguments = {
1111
- inViewportOnly: z10.boolean().optional().describe(
1112
- "Only return elements within the visible viewport. Default: true. Set to false to get ALL elements on the page."
1113
- ),
1114
- includeContainers: z10.boolean().optional().describe(
1115
- "Include layout containers (ViewGroup, FrameLayout, ScrollView, etc). Default: false. Set to true to see all elements including layouts."
1116
- ),
1117
- elementType: z10.enum(["interactable", "visual", "all"]).optional().describe(
1118
- 'Type of elements to return: "interactable" (default) for buttons/links/inputs, "visual" for images/SVGs, "all" for both.'
1119
- ),
1120
- limit: z10.number().optional().describe(
1121
- "Maximum number of elements to return. Default: 0 (unlimited). Set a limit for pages with many elements."
1122
- )
1201
+ var getVisibleElementsToolDefinition = {
1202
+ name: "get_visible_elements",
1203
+ 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',
1204
+ inputSchema: {
1205
+ inViewportOnly: z10.boolean().optional().describe(
1206
+ "Only return elements within the visible viewport. Default: true. Set to false to get ALL elements on the page."
1207
+ ),
1208
+ includeContainers: z10.boolean().optional().describe(
1209
+ "Include layout containers (ViewGroup, FrameLayout, ScrollView, etc). Default: false. Set to true to see all elements including layouts."
1210
+ ),
1211
+ includeBounds: z10.boolean().optional().describe(
1212
+ "Include element bounds/coordinates (x, y, width, height). Default: false. Set to true for coordinate-based interactions or layout debugging."
1213
+ ),
1214
+ elementType: z10.enum(["interactable", "visual", "all"]).optional().describe(
1215
+ 'Type of elements to return: "interactable" (default) for buttons/links/inputs, "visual" for images/SVGs, "all" for both.'
1216
+ ),
1217
+ limit: z10.number().optional().describe("Maximum number of elements to return. Default: 0 (unlimited)."),
1218
+ offset: z10.number().optional().describe("Number of elements to skip (for pagination). Default: 0.")
1219
+ }
1123
1220
  };
1124
1221
  var getVisibleElementsTool = async (args) => {
1125
1222
  try {
@@ -1127,34 +1224,37 @@ var getVisibleElementsTool = async (args) => {
1127
1224
  const {
1128
1225
  inViewportOnly = true,
1129
1226
  includeContainers = false,
1227
+ includeBounds = false,
1130
1228
  elementType = "interactable",
1131
- limit = 0
1229
+ limit = 0,
1230
+ offset = 0
1132
1231
  } = args || {};
1232
+ let elements;
1133
1233
  if (browser.isAndroid || browser.isIOS) {
1134
1234
  const platform = browser.isAndroid ? "android" : "ios";
1135
- let elements2 = await getMobileVisibleElements(browser, platform, {
1136
- includeContainers
1137
- });
1138
- if (inViewportOnly) {
1139
- elements2 = elements2.filter((el) => el.isInViewport);
1140
- }
1141
- if (limit > 0 && elements2.length > limit) {
1142
- elements2 = elements2.slice(0, limit);
1143
- }
1144
- return {
1145
- content: [{ type: "text", text: encode(elements2) }]
1146
- };
1235
+ elements = await getMobileVisibleElements(browser, platform, { includeContainers, includeBounds });
1236
+ } else {
1237
+ const raw = await browser.execute(get_interactable_elements_default, elementType);
1238
+ elements = stripUndefinedFromArray(raw);
1147
1239
  }
1148
- let elements = await browser.execute(get_interactable_elements_default, elementType);
1149
1240
  if (inViewportOnly) {
1150
1241
  elements = elements.filter((el) => el.isInViewport !== false);
1151
1242
  }
1152
- if (limit > 0 && elements.length > limit) {
1243
+ const total = elements.length;
1244
+ if (offset > 0) {
1245
+ elements = elements.slice(offset);
1246
+ }
1247
+ if (limit > 0) {
1153
1248
  elements = elements.slice(0, limit);
1154
1249
  }
1155
- const cleanedElements = stripUndefinedFromArray(elements);
1250
+ const result = {
1251
+ total,
1252
+ showing: elements.length,
1253
+ hasMore: offset + elements.length < total,
1254
+ elements
1255
+ };
1156
1256
  return {
1157
- content: [{ type: "text", text: encode(cleanedElements) }]
1257
+ content: [{ type: "text", text: encode(result) }]
1158
1258
  };
1159
1259
  } catch (e) {
1160
1260
  return {
@@ -1165,8 +1265,12 @@ var getVisibleElementsTool = async (args) => {
1165
1265
 
1166
1266
  // src/tools/take-screenshot.tool.ts
1167
1267
  import { z as z11 } from "zod";
1168
- var takeScreenshotToolArguments = {
1169
- outputPath: z11.string().optional().describe("Optional path where to save the screenshot. If not provided, returns base64 data.")
1268
+ var takeScreenshotToolDefinition = {
1269
+ name: "take_screenshot",
1270
+ description: "captures a screenshot of the current page",
1271
+ inputSchema: {
1272
+ outputPath: z11.string().optional().describe("Optional path where to save the screenshot. If not provided, returns base64 data.")
1273
+ }
1170
1274
  };
1171
1275
  var takeScreenshotTool = async ({ outputPath }) => {
1172
1276
  try {
@@ -1194,8 +1298,12 @@ var takeScreenshotTool = async ({ outputPath }) => {
1194
1298
 
1195
1299
  // src/tools/cookies.tool.ts
1196
1300
  import { z as z12 } from "zod";
1197
- var getCookiesToolArguments = {
1198
- name: z12.string().optional().describe("Optional cookie name to retrieve a specific cookie. If not provided, returns all cookies")
1301
+ var getCookiesToolDefinition = {
1302
+ name: "get_cookies",
1303
+ description: "gets all cookies or a specific cookie by name",
1304
+ inputSchema: {
1305
+ name: z12.string().optional().describe("Optional cookie name to retrieve a specific cookie. If not provided, returns all cookies")
1306
+ }
1199
1307
  };
1200
1308
  var getCookiesTool = async ({ name }) => {
1201
1309
  try {
@@ -1226,15 +1334,19 @@ var getCookiesTool = async ({ name }) => {
1226
1334
  };
1227
1335
  }
1228
1336
  };
1229
- var setCookieToolArguments = {
1230
- name: z12.string().describe("Cookie name"),
1231
- value: z12.string().describe("Cookie value"),
1232
- domain: z12.string().optional().describe("Cookie domain (defaults to current domain)"),
1233
- path: z12.string().optional().describe('Cookie path (defaults to "/")'),
1234
- expires: z12.number().optional().describe("Expiry date as Unix timestamp in seconds"),
1235
- httpOnly: z12.boolean().optional().describe("HttpOnly flag"),
1236
- secure: z12.boolean().optional().describe("Secure flag"),
1237
- sameSite: z12.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute")
1337
+ var setCookieToolDefinition = {
1338
+ name: "set_cookie",
1339
+ description: "sets a cookie with specified name, value, and optional attributes",
1340
+ inputSchema: {
1341
+ name: z12.string().describe("Cookie name"),
1342
+ value: z12.string().describe("Cookie value"),
1343
+ domain: z12.string().optional().describe("Cookie domain (defaults to current domain)"),
1344
+ path: z12.string().optional().describe('Cookie path (defaults to "/")'),
1345
+ expires: z12.number().optional().describe("Expiry date as Unix timestamp in seconds"),
1346
+ httpOnly: z12.boolean().optional().describe("HttpOnly flag"),
1347
+ secure: z12.boolean().optional().describe("Secure flag"),
1348
+ sameSite: z12.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute")
1349
+ }
1238
1350
  };
1239
1351
  var setCookieTool = async ({
1240
1352
  name,
@@ -1268,8 +1380,12 @@ var setCookieTool = async ({
1268
1380
  };
1269
1381
  }
1270
1382
  };
1271
- var deleteCookiesToolArguments = {
1272
- name: z12.string().optional().describe("Optional cookie name to delete a specific cookie. If not provided, deletes all cookies")
1383
+ var deleteCookiesToolDefinition = {
1384
+ name: "delete_cookies",
1385
+ description: "deletes all cookies or a specific cookie by name",
1386
+ inputSchema: {
1387
+ name: z12.string().optional().describe("Optional cookie name to delete a specific cookie. If not provided, deletes all cookies")
1388
+ }
1273
1389
  };
1274
1390
  var deleteCookiesTool = async ({ name }) => {
1275
1391
  try {
@@ -1294,10 +1410,15 @@ var deleteCookiesTool = async ({ name }) => {
1294
1410
  // src/tools/get-accessibility-tree.tool.ts
1295
1411
  import { encode as encode2 } from "@toon-format/toon";
1296
1412
  import { z as z13 } from "zod";
1297
- var getAccessibilityToolArguments = {
1298
- limit: z13.number().optional().describe("Maximum number of nodes to return. Default: 100. Use 0 for unlimited."),
1299
- roles: z13.array(z13.string()).optional().describe('Filter to specific roles (e.g., ["button", "link", "textbox"]). Default: all roles.'),
1300
- namedOnly: z13.boolean().optional().describe("Only return nodes with a name/label. Default: true. Filters out anonymous containers.")
1413
+ var getAccessibilityToolDefinition = {
1414
+ name: "get_accessibility",
1415
+ 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.",
1416
+ inputSchema: {
1417
+ limit: z13.number().optional().describe("Maximum number of nodes to return. Default: 100. Use 0 for unlimited."),
1418
+ offset: z13.number().optional().describe("Number of nodes to skip (for pagination). Default: 0."),
1419
+ roles: z13.array(z13.string()).optional().describe('Filter to specific roles (e.g., ["button", "link", "textbox"]). Default: all roles.'),
1420
+ namedOnly: z13.boolean().optional().describe("Only return nodes with a name/label. Default: true. Filters out anonymous containers.")
1421
+ }
1301
1422
  };
1302
1423
  function flattenAccessibilityTree(node, result = []) {
1303
1424
  if (!node) return result;
@@ -1348,7 +1469,7 @@ var getAccessibilityTreeTool = async (args) => {
1348
1469
  }]
1349
1470
  };
1350
1471
  }
1351
- const { limit = 100, roles, namedOnly = true } = args || {};
1472
+ const { limit = 100, offset = 0, roles, namedOnly = true } = args || {};
1352
1473
  const puppeteer = await browser.getPuppeteer();
1353
1474
  const pages = await puppeteer.pages();
1354
1475
  if (pages.length === 0) {
@@ -1374,14 +1495,21 @@ var getAccessibilityTreeTool = async (args) => {
1374
1495
  const roleSet = new Set(roles.map((r) => r.toLowerCase()));
1375
1496
  nodes = nodes.filter((n) => n.role && roleSet.has(n.role.toLowerCase()));
1376
1497
  }
1377
- if (limit > 0 && nodes.length > limit) {
1498
+ const total = nodes.length;
1499
+ if (offset > 0) {
1500
+ nodes = nodes.slice(offset);
1501
+ }
1502
+ if (limit > 0) {
1378
1503
  nodes = nodes.slice(0, limit);
1379
1504
  }
1505
+ const result = {
1506
+ total,
1507
+ showing: nodes.length,
1508
+ hasMore: offset + nodes.length < total,
1509
+ nodes
1510
+ };
1380
1511
  return {
1381
- content: [{
1382
- type: "text",
1383
- text: encode2(nodes)
1384
- }]
1512
+ content: [{ type: "text", text: encode2(result) }]
1385
1513
  };
1386
1514
  } catch (e) {
1387
1515
  return {
@@ -1472,22 +1600,26 @@ function buildAndroidCapabilities(appPath, options) {
1472
1600
  }
1473
1601
 
1474
1602
  // src/tools/app-session.tool.ts
1475
- var startAppToolArguments = {
1476
- platform: z14.enum(["iOS", "Android"]).describe("Mobile platform"),
1477
- appPath: z14.string().optional().describe("Path to the app file (.app/.apk/.ipa). Required unless noReset=true (connecting to already-running app)"),
1478
- deviceName: z14.string().describe("Device/emulator/simulator name"),
1479
- platformVersion: z14.string().optional().describe('OS version (e.g., "17.0", "14")'),
1480
- automationName: z14.enum(["XCUITest", "UiAutomator2", "Espresso"]).optional().describe("Automation driver name"),
1481
- appiumHost: z14.string().optional().describe("Appium server hostname (overrides APPIUM_URL env var)"),
1482
- appiumPort: z14.number().optional().describe("Appium server port (overrides APPIUM_URL_PORT env var)"),
1483
- appiumPath: z14.string().optional().describe("Appium server path (overrides APPIUM_PATH env var)"),
1484
- autoGrantPermissions: z14.boolean().optional().describe("Auto-grant app permissions (default: true)"),
1485
- autoAcceptAlerts: z14.boolean().optional().describe("Auto-accept alerts (default: true)"),
1486
- autoDismissAlerts: z14.boolean().optional().describe('Auto-dismiss alerts (default: false, will override "autoAcceptAlerts" to undefined if set)'),
1487
- appWaitActivity: z14.string().optional().describe("Activity to wait for on launch (Android only)"),
1488
- udid: z14.string().optional().describe('Unique Device Identifier for iOS real device testing (e.g., "00008030-001234567890002E")'),
1489
- noReset: z14.boolean().optional().describe("Do not reset app state before session (preserves app data). Default: false"),
1490
- fullReset: z14.boolean().optional().describe("Uninstall app before/after session. Default: true. Set to false with noReset=true to preserve app state completely")
1603
+ var startAppToolDefinition = {
1604
+ name: "start_app_session",
1605
+ description: "starts a mobile app session (iOS/Android) via Appium",
1606
+ inputSchema: {
1607
+ platform: z14.enum(["iOS", "Android"]).describe("Mobile platform"),
1608
+ appPath: z14.string().optional().describe("Path to the app file (.app/.apk/.ipa). Required unless noReset=true (connecting to already-running app)"),
1609
+ deviceName: z14.string().describe("Device/emulator/simulator name"),
1610
+ platformVersion: z14.string().optional().describe('OS version (e.g., "17.0", "14")'),
1611
+ automationName: z14.enum(["XCUITest", "UiAutomator2", "Espresso"]).optional().describe("Automation driver name"),
1612
+ appiumHost: z14.string().optional().describe("Appium server hostname (overrides APPIUM_URL env var)"),
1613
+ appiumPort: z14.number().optional().describe("Appium server port (overrides APPIUM_URL_PORT env var)"),
1614
+ appiumPath: z14.string().optional().describe("Appium server path (overrides APPIUM_PATH env var)"),
1615
+ autoGrantPermissions: z14.boolean().optional().describe("Auto-grant app permissions (default: true)"),
1616
+ autoAcceptAlerts: z14.boolean().optional().describe("Auto-accept alerts (default: true)"),
1617
+ autoDismissAlerts: z14.boolean().optional().describe('Auto-dismiss alerts (default: false, will override "autoAcceptAlerts" to undefined if set)'),
1618
+ appWaitActivity: z14.string().optional().describe("Activity to wait for on launch (Android only)"),
1619
+ udid: z14.string().optional().describe('Unique Device Identifier for iOS real device testing (e.g., "00008030-001234567890002E")'),
1620
+ noReset: z14.boolean().optional().describe("Do not reset app state before session (preserves app data). Default: false"),
1621
+ fullReset: z14.boolean().optional().describe("Uninstall app before/after session. Default: true. Set to false with noReset=true to preserve app state completely")
1622
+ }
1491
1623
  };
1492
1624
  var getState = () => {
1493
1625
  const sharedState = getBrowser.__state;
@@ -1588,10 +1720,14 @@ Appium Server: ${serverConfig.hostname}:${serverConfig.port}${serverConfig.path}
1588
1720
 
1589
1721
  // src/tools/gestures.tool.ts
1590
1722
  import { z as z15 } from "zod";
1591
- var tapElementToolArguments = {
1592
- selector: z15.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1593
- x: z15.number().optional().describe("X coordinate for tap (if no selector provided)"),
1594
- y: z15.number().optional().describe("Y coordinate for tap (if no selector provided)")
1723
+ var tapElementToolDefinition = {
1724
+ name: "tap_element",
1725
+ description: "taps an element by selector or coordinates (mobile)",
1726
+ inputSchema: {
1727
+ selector: z15.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1728
+ x: z15.number().optional().describe("X coordinate for tap (if no selector provided)"),
1729
+ y: z15.number().optional().describe("Y coordinate for tap (if no selector provided)")
1730
+ }
1595
1731
  };
1596
1732
  var tapElementTool = async (args) => {
1597
1733
  try {
@@ -1622,12 +1758,16 @@ var tapElementTool = async (args) => {
1622
1758
  };
1623
1759
  }
1624
1760
  };
1625
- var swipeToolArguments = {
1626
- direction: z15.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
1627
- duration: z15.number().min(100).max(5e3).optional().describe("Swipe duration in milliseconds (default: 500)"),
1628
- startX: z15.number().optional().describe("Start X coordinate (optional, uses screen center)"),
1629
- startY: z15.number().optional().describe("Start Y coordinate (optional, uses screen center)"),
1630
- distance: z15.number().optional().describe("Swipe distance in pixels (optional, uses percentage of screen)")
1761
+ var swipeToolDefinition = {
1762
+ name: "swipe",
1763
+ description: "performs a swipe gesture in specified direction (mobile)",
1764
+ inputSchema: {
1765
+ direction: z15.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
1766
+ duration: z15.number().min(100).max(5e3).optional().describe("Swipe duration in milliseconds (default: 500)"),
1767
+ startX: z15.number().optional().describe("Start X coordinate (optional, uses screen center)"),
1768
+ startY: z15.number().optional().describe("Start Y coordinate (optional, uses screen center)"),
1769
+ distance: z15.number().optional().describe("Swipe distance in pixels (optional, uses percentage of screen)")
1770
+ }
1631
1771
  };
1632
1772
  var swipeTool = async (args) => {
1633
1773
  try {
@@ -1675,11 +1815,15 @@ var swipeTool = async (args) => {
1675
1815
  };
1676
1816
  }
1677
1817
  };
1678
- var longPressToolArguments = {
1679
- selector: z15.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1680
- x: z15.number().optional().describe("X coordinate for long press (if no selector provided)"),
1681
- y: z15.number().optional().describe("Y coordinate for long press (if no selector provided)"),
1682
- duration: z15.number().min(500).max(1e4).optional().describe("Long press duration in milliseconds (default: 1000)")
1818
+ var longPressToolDefinition = {
1819
+ name: "long_press",
1820
+ description: "performs a long press on element or coordinates (mobile)",
1821
+ inputSchema: {
1822
+ selector: z15.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1823
+ x: z15.number().optional().describe("X coordinate for long press (if no selector provided)"),
1824
+ y: z15.number().optional().describe("Y coordinate for long press (if no selector provided)"),
1825
+ duration: z15.number().min(500).max(1e4).optional().describe("Long press duration in milliseconds (default: 1000)")
1826
+ }
1683
1827
  };
1684
1828
  var longPressTool = async (args) => {
1685
1829
  try {
@@ -1714,14 +1858,18 @@ var longPressTool = async (args) => {
1714
1858
  };
1715
1859
  }
1716
1860
  };
1717
- var dragAndDropToolArguments = {
1718
- fromSelector: z15.string().optional().describe("Source element selector"),
1719
- fromX: z15.number().optional().describe("Source X coordinate"),
1720
- fromY: z15.number().optional().describe("Source Y coordinate"),
1721
- toSelector: z15.string().optional().describe("Target element selector"),
1722
- toX: z15.number().optional().describe("Target X coordinate"),
1723
- toY: z15.number().optional().describe("Target Y coordinate"),
1724
- duration: z15.number().min(100).max(5e3).optional().describe("Drag duration in milliseconds (default: 500)")
1861
+ var dragAndDropToolDefinition = {
1862
+ name: "drag_and_drop",
1863
+ description: "drags from one location to another (mobile)",
1864
+ inputSchema: {
1865
+ fromSelector: z15.string().optional().describe("Source element selector"),
1866
+ fromX: z15.number().optional().describe("Source X coordinate"),
1867
+ fromY: z15.number().optional().describe("Source Y coordinate"),
1868
+ toSelector: z15.string().optional().describe("Target element selector"),
1869
+ toX: z15.number().optional().describe("Target X coordinate"),
1870
+ toY: z15.number().optional().describe("Target Y coordinate"),
1871
+ duration: z15.number().min(100).max(5e3).optional().describe("Drag duration in milliseconds (default: 500)")
1872
+ }
1725
1873
  };
1726
1874
  var dragAndDropTool = async (args) => {
1727
1875
  try {
@@ -1782,8 +1930,12 @@ var dragAndDropTool = async (args) => {
1782
1930
 
1783
1931
  // src/tools/app-actions.tool.ts
1784
1932
  import { z as z16 } from "zod";
1785
- var getAppStateToolArguments = {
1786
- bundleId: z16.string().describe("App bundle ID (e.g., com.example.app)")
1933
+ var getAppStateToolDefinition = {
1934
+ name: "get_app_state",
1935
+ description: "gets the state of an app (not installed, not running, background, foreground)",
1936
+ inputSchema: {
1937
+ bundleId: z16.string().describe("App bundle ID (e.g., com.example.app)")
1938
+ }
1787
1939
  };
1788
1940
  var getAppStateTool = async (args) => {
1789
1941
  try {
@@ -1812,8 +1964,12 @@ var getAppStateTool = async (args) => {
1812
1964
  };
1813
1965
  }
1814
1966
  };
1815
- var activateAppToolArguments = {
1816
- bundleId: z16.string().describe("App bundle ID to activate (e.g., com.example.app)")
1967
+ var activateAppToolDefinition = {
1968
+ name: "activate_app",
1969
+ description: "activates/brings an app to foreground",
1970
+ inputSchema: {
1971
+ bundleId: z16.string().describe("App bundle ID to activate (e.g., com.example.app)")
1972
+ }
1817
1973
  };
1818
1974
  var activateAppTool = async (args) => {
1819
1975
  try {
@@ -1830,8 +1986,12 @@ var activateAppTool = async (args) => {
1830
1986
  };
1831
1987
  }
1832
1988
  };
1833
- var terminateAppToolArguments = {
1834
- bundleId: z16.string().describe("App bundle ID to terminate (e.g., com.example.app)")
1989
+ var terminateAppToolDefinition = {
1990
+ name: "terminate_app",
1991
+ description: "terminates a running app",
1992
+ inputSchema: {
1993
+ bundleId: z16.string().describe("App bundle ID to terminate (e.g., com.example.app)")
1994
+ }
1835
1995
  };
1836
1996
  var terminateAppTool = async (args) => {
1837
1997
  try {
@@ -1851,6 +2011,25 @@ var terminateAppTool = async (args) => {
1851
2011
 
1852
2012
  // src/tools/context.tool.ts
1853
2013
  import { z as z17 } from "zod";
2014
+ var getContextsToolDefinition = {
2015
+ name: "get_contexts",
2016
+ description: "lists available contexts (NATIVE_APP, WEBVIEW)",
2017
+ inputSchema: {}
2018
+ };
2019
+ var getCurrentContextToolDefinition = {
2020
+ name: "get_current_context",
2021
+ description: "shows the currently active context",
2022
+ inputSchema: {}
2023
+ };
2024
+ var switchContextToolDefinition = {
2025
+ name: "switch_context",
2026
+ description: "switches between native and webview contexts",
2027
+ inputSchema: {
2028
+ context: z17.string().describe(
2029
+ 'Context name to switch to (e.g., "NATIVE_APP", "WEBVIEW_com.example.app", or use index from get_contexts)'
2030
+ )
2031
+ }
2032
+ };
1854
2033
  var getContextsTool = async () => {
1855
2034
  try {
1856
2035
  const browser = getBrowser();
@@ -1883,11 +2062,6 @@ var getCurrentContextTool = async () => {
1883
2062
  };
1884
2063
  }
1885
2064
  };
1886
- var switchContextToolArguments = {
1887
- context: z17.string().describe(
1888
- 'Context name to switch to (e.g., "NATIVE_APP", "WEBVIEW_com.example.app", or use index from get_contexts)'
1889
- )
1890
- };
1891
2065
  var switchContextTool = async (args) => {
1892
2066
  try {
1893
2067
  const browser = getBrowser();
@@ -1922,6 +2096,86 @@ var switchContextTool = async (args) => {
1922
2096
 
1923
2097
  // src/tools/device.tool.ts
1924
2098
  import { z as z18 } from "zod";
2099
+ var getDeviceInfoToolDefinition = {
2100
+ name: "get_device_info",
2101
+ description: "gets device information (platform, version, screen size)",
2102
+ inputSchema: {}
2103
+ };
2104
+ var getOrientationToolDefinition = {
2105
+ name: "get_orientation",
2106
+ description: "gets current device orientation",
2107
+ inputSchema: {}
2108
+ };
2109
+ var lockDeviceToolDefinition = {
2110
+ name: "lock_device",
2111
+ description: "locks the device screen",
2112
+ inputSchema: {}
2113
+ };
2114
+ var unlockDeviceToolDefinition = {
2115
+ name: "unlock_device",
2116
+ description: "unlocks the device screen",
2117
+ inputSchema: {}
2118
+ };
2119
+ var isDeviceLockedToolDefinition = {
2120
+ name: "is_device_locked",
2121
+ description: "checks if device is locked",
2122
+ inputSchema: {}
2123
+ };
2124
+ var shakeDeviceToolDefinition = {
2125
+ name: "shake_device",
2126
+ description: "shakes the device (iOS only)",
2127
+ inputSchema: {}
2128
+ };
2129
+ var hideKeyboardToolDefinition = {
2130
+ name: "hide_keyboard",
2131
+ description: "hides the on-screen keyboard",
2132
+ inputSchema: {}
2133
+ };
2134
+ var isKeyboardShownToolDefinition = {
2135
+ name: "is_keyboard_shown",
2136
+ description: "checks if keyboard is visible",
2137
+ inputSchema: {}
2138
+ };
2139
+ var openNotificationsToolDefinition = {
2140
+ name: "open_notifications",
2141
+ description: "opens the notifications panel (Android only)",
2142
+ inputSchema: {}
2143
+ };
2144
+ var getGeolocationToolDefinition = {
2145
+ name: "get_geolocation",
2146
+ description: "gets current device geolocation",
2147
+ inputSchema: {}
2148
+ };
2149
+ var rotateDeviceToolDefinition = {
2150
+ name: "rotate_device",
2151
+ description: "rotates device to portrait or landscape orientation",
2152
+ inputSchema: {
2153
+ orientation: z18.enum(["PORTRAIT", "LANDSCAPE"]).describe("Device orientation")
2154
+ }
2155
+ };
2156
+ var sendKeysToolDefinition = {
2157
+ name: "send_keys",
2158
+ description: "sends keys to the app (Android only)",
2159
+ inputSchema: {
2160
+ keys: z18.array(z18.string()).describe('Array of keys to send (e.g., ["h", "e", "l", "l", "o"])')
2161
+ }
2162
+ };
2163
+ var pressKeyCodeToolDefinition = {
2164
+ name: "press_key_code",
2165
+ description: "presses an Android key code (Android only)",
2166
+ inputSchema: {
2167
+ keyCode: z18.number().describe("Android key code (e.g., 4 for BACK, 3 for HOME)")
2168
+ }
2169
+ };
2170
+ var setGeolocationToolDefinition = {
2171
+ name: "set_geolocation",
2172
+ description: "sets device geolocation (latitude, longitude, altitude)",
2173
+ inputSchema: {
2174
+ latitude: z18.number().min(-90).max(90).describe("Latitude coordinate"),
2175
+ longitude: z18.number().min(-180).max(180).describe("Longitude coordinate"),
2176
+ altitude: z18.number().optional().describe("Altitude in meters (optional)")
2177
+ }
2178
+ };
1925
2179
  var getDeviceInfoTool = async () => {
1926
2180
  try {
1927
2181
  const browser = getBrowser();
@@ -1949,9 +2203,6 @@ ${Object.entries(info).map(([key, value]) => ` ${key}: ${value}`).join("\n")}`
1949
2203
  };
1950
2204
  }
1951
2205
  };
1952
- var rotateDeviceToolArguments = {
1953
- orientation: z18.enum(["PORTRAIT", "LANDSCAPE"]).describe("Device orientation")
1954
- };
1955
2206
  var rotateDeviceTool = async (args) => {
1956
2207
  try {
1957
2208
  const browser = getBrowser();
@@ -2031,9 +2282,6 @@ var shakeDeviceTool = async () => {
2031
2282
  };
2032
2283
  }
2033
2284
  };
2034
- var sendKeysToolArguments = {
2035
- keys: z18.array(z18.string()).describe('Array of keys to send (e.g., ["h", "e", "l", "l", "o"])')
2036
- };
2037
2285
  var sendKeysTool = async (args) => {
2038
2286
  try {
2039
2287
  const browser = getBrowser();
@@ -2048,9 +2296,6 @@ var sendKeysTool = async (args) => {
2048
2296
  };
2049
2297
  }
2050
2298
  };
2051
- var pressKeyCodeToolArguments = {
2052
- keyCode: z18.number().describe("Android key code (e.g., 4 for BACK, 3 for HOME)")
2053
- };
2054
2299
  var pressKeyCodeTool = async (args) => {
2055
2300
  try {
2056
2301
  const browser = getBrowser();
@@ -2125,11 +2370,6 @@ var getGeolocationTool = async () => {
2125
2370
  };
2126
2371
  }
2127
2372
  };
2128
- var setGeolocationToolArguments = {
2129
- latitude: z18.number().min(-90).max(90).describe("Latitude coordinate"),
2130
- longitude: z18.number().min(-180).max(180).describe("Longitude coordinate"),
2131
- altitude: z18.number().optional().describe("Altitude in meters (optional)")
2132
- };
2133
2373
  var setGeolocationTool = async (args) => {
2134
2374
  try {
2135
2375
  const browser = getBrowser();
@@ -2153,62 +2393,129 @@ var setGeolocationTool = async (args) => {
2153
2393
  }
2154
2394
  };
2155
2395
 
2396
+ // package.json
2397
+ var package_default = {
2398
+ name: "@wdio/mcp",
2399
+ author: "Vince Graics",
2400
+ repository: {
2401
+ type: "git",
2402
+ url: "git://github.com/webdriverio/mcp.git"
2403
+ },
2404
+ version: "1.5.1",
2405
+ description: "MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)",
2406
+ main: "./lib/server.js",
2407
+ module: "./lib/server.js",
2408
+ types: "./lib/server.d.ts",
2409
+ bin: {
2410
+ "wdio-mcp": "lib/server.js"
2411
+ },
2412
+ license: "MIT",
2413
+ publishConfig: {
2414
+ access: "public"
2415
+ },
2416
+ type: "module",
2417
+ files: [
2418
+ "lib",
2419
+ "README.md"
2420
+ ],
2421
+ scripts: {
2422
+ prebundle: "rimraf lib --glob ./*.tgz",
2423
+ bundle: "tsup && shx chmod +x lib/server.js",
2424
+ postbundle: "npm pack",
2425
+ lint: "eslint src/ --fix && tsc --noEmit",
2426
+ start: "node lib/server.js",
2427
+ dev: "tsx --watch src/server.ts",
2428
+ prepare: "husky"
2429
+ },
2430
+ dependencies: {
2431
+ "@modelcontextprotocol/sdk": "1.25",
2432
+ "@toon-format/toon": "^2.1.0",
2433
+ "@wdio/protocols": "^9.16.2",
2434
+ "@xmldom/xmldom": "^0.8.11",
2435
+ "puppeteer-core": "^24.35.0",
2436
+ webdriverio: "9.23",
2437
+ zod: "^4.3.5"
2438
+ },
2439
+ devDependencies: {
2440
+ "@release-it/conventional-changelog": "^10.0.4",
2441
+ "@types/node": "^20.11.0",
2442
+ "@wdio/eslint": "^0.1.3",
2443
+ "@wdio/types": "^9.20.0",
2444
+ eslint: "^9.39.2",
2445
+ husky: "^9.1.7",
2446
+ "release-it": "^19.2.3",
2447
+ rimraf: "^6.1.2",
2448
+ shx: "^0.4.0",
2449
+ tsup: "^8.5.1",
2450
+ tsx: "^4.21.0",
2451
+ typescript: "5.9"
2452
+ },
2453
+ packageManager: "pnpm@10.12.4"
2454
+ };
2455
+
2156
2456
  // src/server.ts
2157
2457
  console.log = (...args) => console.error("[LOG]", ...args);
2158
2458
  console.info = (...args) => console.error("[INFO]", ...args);
2159
2459
  console.warn = (...args) => console.error("[WARN]", ...args);
2160
2460
  console.debug = (...args) => console.error("[DEBUG]", ...args);
2161
2461
  var server = new McpServer({
2162
- name: "MCP WebdriverIO",
2163
- version: "1.4.0"
2462
+ title: "WebdriverIO MCP Server",
2463
+ name: package_default.name,
2464
+ version: package_default.version,
2465
+ description: package_default.description,
2466
+ websiteUrl: "https://github.com/webdriverio/mcp"
2164
2467
  }, {
2468
+ 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.",
2165
2469
  capabilities: {
2166
- resources: {},
2167
2470
  tools: {}
2168
2471
  }
2169
2472
  });
2170
- server.tool("start_browser", "starts a browser session and sets it to the current state", startBrowserToolArguments, startBrowserTool);
2171
- server.tool("start_app_session", "starts a mobile app session (iOS/Android) via Appium", startAppToolArguments, startAppTool);
2172
- server.tool("close_session", "closes or detaches from the current browser or app session", closeSessionToolArguments, closeSessionTool);
2173
- server.tool("navigate", "navigates to a URL", navigateToolArguments, navigateTool);
2174
- server.tool("get_visible_elements", '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', getVisibleElementsToolArguments, getVisibleElementsTool);
2175
- server.tool("get_accessibility", "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.", getAccessibilityToolArguments, getAccessibilityTreeTool);
2176
- server.tool("scroll_down", "scrolls the page down by specified pixels", scrollDownToolArguments, scrollDownTool);
2177
- server.tool("scroll_up", "scrolls the page up by specified pixels", scrollUpToolArguments, scrollUpTool);
2178
- server.tool("find_element", "finds an element", findElementToolArguments, findElementTool);
2179
- server.tool("click_element", "clicks an element", clickToolArguments, clickTool);
2180
- server.tool("click_via_text", "clicks an element", clickToolArguments, clickToolViaText);
2181
- server.tool("set_value", "set value to an element, aka typing", setValueToolArguments, setValueTool);
2182
- server.tool("get_element_text", "gets the text content of an element", getElementTextToolArguments, getElementTextTool);
2183
- server.tool("is_displayed", "checks if an element is displayed", isDisplayedToolArguments, isDisplayedTool);
2184
- server.tool("take_screenshot", "captures a screenshot of the current page", takeScreenshotToolArguments, takeScreenshotTool);
2185
- server.tool("get_cookies", "gets all cookies or a specific cookie by name", getCookiesToolArguments, getCookiesTool);
2186
- server.tool("set_cookie", "sets a cookie with specified name, value, and optional attributes", setCookieToolArguments, setCookieTool);
2187
- server.tool("delete_cookies", "deletes all cookies or a specific cookie by name", deleteCookiesToolArguments, deleteCookiesTool);
2188
- server.tool("tap_element", "taps an element by selector or coordinates (mobile)", tapElementToolArguments, tapElementTool);
2189
- server.tool("swipe", "performs a swipe gesture in specified direction (mobile)", swipeToolArguments, swipeTool);
2190
- server.tool("long_press", "performs a long press on element or coordinates (mobile)", longPressToolArguments, longPressTool);
2191
- server.tool("drag_and_drop", "drags from one location to another (mobile)", dragAndDropToolArguments, dragAndDropTool);
2192
- server.tool("get_app_state", "gets the state of an app (not installed, not running, background, foreground)", getAppStateToolArguments, getAppStateTool);
2193
- server.tool("activate_app", "activates/brings an app to foreground", activateAppToolArguments, activateAppTool);
2194
- server.tool("terminate_app", "terminates a running app", terminateAppToolArguments, terminateAppTool);
2195
- server.tool("get_contexts", "lists available contexts (NATIVE_APP, WEBVIEW)", {}, getContextsTool);
2196
- server.tool("get_current_context", "shows the currently active context", {}, getCurrentContextTool);
2197
- server.tool("switch_context", "switches between native and webview contexts", switchContextToolArguments, switchContextTool);
2198
- server.tool("get_device_info", "gets device information (platform, version, screen size)", {}, getDeviceInfoTool);
2199
- server.tool("rotate_device", "rotates device to portrait or landscape orientation", rotateDeviceToolArguments, rotateDeviceTool);
2200
- server.tool("get_orientation", "gets current device orientation", {}, getOrientationTool);
2201
- server.tool("lock_device", "locks the device screen", {}, lockDeviceTool);
2202
- server.tool("unlock_device", "unlocks the device screen", {}, unlockDeviceTool);
2203
- server.tool("is_device_locked", "checks if device is locked", {}, isDeviceLockedTool);
2204
- server.tool("shake_device", "shakes the device (iOS only)", {}, shakeDeviceTool);
2205
- server.tool("send_keys", "sends keys to the app (Android only)", sendKeysToolArguments, sendKeysTool);
2206
- server.tool("press_key_code", "presses an Android key code (Android only)", pressKeyCodeToolArguments, pressKeyCodeTool);
2207
- server.tool("hide_keyboard", "hides the on-screen keyboard", {}, hideKeyboardTool);
2208
- server.tool("is_keyboard_shown", "checks if keyboard is visible", {}, isKeyboardShownTool);
2209
- server.tool("open_notifications", "opens the notifications panel (Android only)", {}, openNotificationsTool);
2210
- server.tool("get_geolocation", "gets current device geolocation", {}, getGeolocationTool);
2211
- server.tool("set_geolocation", "sets device geolocation (latitude, longitude, altitude)", setGeolocationToolArguments, setGeolocationTool);
2473
+ var registerTool = (definition, callback) => server.registerTool(definition.name, {
2474
+ description: definition.description,
2475
+ inputSchema: definition.inputSchema
2476
+ }, callback);
2477
+ registerTool(startBrowserToolDefinition, startBrowserTool);
2478
+ registerTool(startAppToolDefinition, startAppTool);
2479
+ registerTool(closeSessionToolDefinition, closeSessionTool);
2480
+ registerTool(navigateToolDefinition, navigateTool);
2481
+ registerTool(getVisibleElementsToolDefinition, getVisibleElementsTool);
2482
+ registerTool(getAccessibilityToolDefinition, getAccessibilityTreeTool);
2483
+ registerTool(scrollDownToolDefinition, scrollDownTool);
2484
+ registerTool(scrollUpToolDefinition, scrollUpTool);
2485
+ registerTool(findElementToolDefinition, findElementTool);
2486
+ registerTool(clickToolDefinition, clickTool);
2487
+ registerTool(clickViaTextToolDefinition, clickToolViaText);
2488
+ registerTool(setValueToolDefinition, setValueTool);
2489
+ registerTool(getElementTextToolDefinition, getElementTextTool);
2490
+ registerTool(isDisplayedToolDefinition, isDisplayedTool);
2491
+ registerTool(takeScreenshotToolDefinition, takeScreenshotTool);
2492
+ registerTool(getCookiesToolDefinition, getCookiesTool);
2493
+ registerTool(setCookieToolDefinition, setCookieTool);
2494
+ registerTool(deleteCookiesToolDefinition, deleteCookiesTool);
2495
+ registerTool(tapElementToolDefinition, tapElementTool);
2496
+ registerTool(swipeToolDefinition, swipeTool);
2497
+ registerTool(longPressToolDefinition, longPressTool);
2498
+ registerTool(dragAndDropToolDefinition, dragAndDropTool);
2499
+ registerTool(getAppStateToolDefinition, getAppStateTool);
2500
+ registerTool(activateAppToolDefinition, activateAppTool);
2501
+ registerTool(terminateAppToolDefinition, terminateAppTool);
2502
+ registerTool(getContextsToolDefinition, getContextsTool);
2503
+ registerTool(getCurrentContextToolDefinition, getCurrentContextTool);
2504
+ registerTool(switchContextToolDefinition, switchContextTool);
2505
+ registerTool(getDeviceInfoToolDefinition, getDeviceInfoTool);
2506
+ registerTool(rotateDeviceToolDefinition, rotateDeviceTool);
2507
+ registerTool(getOrientationToolDefinition, getOrientationTool);
2508
+ registerTool(lockDeviceToolDefinition, lockDeviceTool);
2509
+ registerTool(unlockDeviceToolDefinition, unlockDeviceTool);
2510
+ registerTool(isDeviceLockedToolDefinition, isDeviceLockedTool);
2511
+ registerTool(shakeDeviceToolDefinition, shakeDeviceTool);
2512
+ registerTool(sendKeysToolDefinition, sendKeysTool);
2513
+ registerTool(pressKeyCodeToolDefinition, pressKeyCodeTool);
2514
+ registerTool(hideKeyboardToolDefinition, hideKeyboardTool);
2515
+ registerTool(isKeyboardShownToolDefinition, isKeyboardShownTool);
2516
+ registerTool(openNotificationsToolDefinition, openNotificationsTool);
2517
+ registerTool(getGeolocationToolDefinition, getGeolocationTool);
2518
+ registerTool(setGeolocationToolDefinition, setGeolocationTool);
2212
2519
  async function main() {
2213
2520
  const transport = new StdioServerTransport();
2214
2521
  await server.connect(transport);