@wdio/mcp 1.4.1 → 1.5.1

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 {
@@ -279,7 +328,7 @@ var scrollUpTool = async ({ pixels = 500 }) => {
279
328
  };
280
329
 
281
330
  // src/scripts/get-interactable-elements.ts
282
- var elementsScript = () => (function() {
331
+ var elementsScript = (elementType = "interactable") => (function() {
283
332
  const interactableSelectors = [
284
333
  "a[href]",
285
334
  // Links with href
@@ -320,6 +369,20 @@ var elementsScript = () => (function() {
320
369
  '[tabindex]:not([tabindex="-1"])'
321
370
  // Elements with tabindex
322
371
  ];
372
+ const visualSelectors = [
373
+ "img",
374
+ // Images
375
+ "picture",
376
+ // Picture elements
377
+ "svg",
378
+ // SVG graphics
379
+ "video",
380
+ // Video elements
381
+ "canvas",
382
+ // Canvas elements
383
+ '[style*="background-image"]'
384
+ // Elements with background images
385
+ ];
323
386
  function isVisible(element) {
324
387
  if (typeof element.checkVisibility === "function") {
325
388
  return element.checkVisibility({
@@ -335,7 +398,7 @@ var elementsScript = () => (function() {
335
398
  if (element.id) {
336
399
  return `#${CSS.escape(element.id)}`;
337
400
  }
338
- if (element.className) {
401
+ if (element.className && typeof element.className === "string") {
339
402
  const classes = element.className.trim().split(/\s+/).filter(Boolean);
340
403
  if (classes.length > 0) {
341
404
  const classSelector = classes.slice(0, 2).map((c) => `.${CSS.escape(c)}`).join("");
@@ -372,9 +435,16 @@ var elementsScript = () => (function() {
372
435
  }
373
436
  return path.join(" > ");
374
437
  }
375
- function getInteractableElements() {
438
+ function getElements() {
439
+ const selectors = [];
440
+ if (elementType === "interactable" || elementType === "all") {
441
+ selectors.push(...interactableSelectors);
442
+ }
443
+ if (elementType === "visual" || elementType === "all") {
444
+ selectors.push(...visualSelectors);
445
+ }
376
446
  const allElements = [];
377
- interactableSelectors.forEach((selector) => {
447
+ selectors.forEach((selector) => {
378
448
  const elements = document.querySelectorAll(selector);
379
449
  elements.forEach((element) => {
380
450
  if (!allElements.includes(element)) {
@@ -383,28 +453,46 @@ var elementsScript = () => (function() {
383
453
  });
384
454
  });
385
455
  const elementInfos = allElements.filter((element) => isVisible(element) && !element.disabled).map((element) => {
386
- const rect = element.getBoundingClientRect();
456
+ const el = element;
457
+ const inputEl = element;
458
+ const rect = el.getBoundingClientRect();
387
459
  const isInViewport = rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth);
388
- return {
389
- tagName: element.tagName.toLowerCase(),
390
- type: element.getAttribute("type") || void 0,
391
- id: element.id || void 0,
392
- className: element.className || void 0,
393
- textContent: element.textContent?.trim() || void 0,
394
- value: element.value || void 0,
395
- placeholder: element.placeholder || void 0,
396
- href: element.getAttribute("href") || void 0,
397
- ariaLabel: element.getAttribute("aria-label") || void 0,
398
- role: element.getAttribute("role") || void 0,
399
- cssSelector: getCssSelector(element),
460
+ const info = {
461
+ tagName: el.tagName.toLowerCase(),
462
+ cssSelector: getCssSelector(el),
400
463
  isInViewport
401
464
  };
465
+ const type = el.getAttribute("type");
466
+ if (type) info.type = type;
467
+ const id = el.id;
468
+ if (id) info.id = id;
469
+ const className = el.className;
470
+ if (className && typeof className === "string") info.className = className;
471
+ const textContent = el.textContent?.trim();
472
+ if (textContent) info.textContent = textContent;
473
+ const value = inputEl.value;
474
+ if (value) info.value = value;
475
+ const placeholder = inputEl.placeholder;
476
+ if (placeholder) info.placeholder = placeholder;
477
+ const href = el.getAttribute("href");
478
+ if (href) info.href = href;
479
+ const ariaLabel = el.getAttribute("aria-label");
480
+ if (ariaLabel) info.ariaLabel = ariaLabel;
481
+ const role = el.getAttribute("role");
482
+ if (role) info.role = role;
483
+ const src = el.getAttribute("src");
484
+ if (src) info.src = src;
485
+ const alt = el.getAttribute("alt");
486
+ if (alt) info.alt = alt;
487
+ if (elementType === "visual" || elementType === "all") {
488
+ const bgImage = window.getComputedStyle(el).backgroundImage;
489
+ if (bgImage && bgImage !== "none") info.backgroundImage = bgImage;
490
+ }
491
+ return info;
402
492
  });
403
- return [
404
- ...elementInfos
405
- ];
493
+ return elementInfos;
406
494
  }
407
- return getInteractableElements();
495
+ return getElements();
408
496
  })();
409
497
  var get_interactable_elements_default = elementsScript;
410
498
 
@@ -1056,18 +1144,45 @@ async function getMobileVisibleElements(browser, platform, options = {}) {
1056
1144
  // src/tools/get-visible-elements.tool.ts
1057
1145
  import { encode } from "@toon-format/toon";
1058
1146
  import { z as z10 } from "zod";
1059
- var getVisibleElementsToolArguments = {
1060
- inViewportOnly: z10.boolean().optional().describe(
1061
- "Only return elements within the visible viewport. Default: true. Set to false to get ALL elements on the page."
1062
- ),
1063
- includeContainers: z10.boolean().optional().describe(
1064
- "Include layout containers (ViewGroup, FrameLayout, ScrollView, etc). Default: false. Set to true to see all elements including layouts."
1065
- )
1147
+
1148
+ // src/utils/strip-undefined.ts
1149
+ function stripUndefined(obj) {
1150
+ return Object.fromEntries(
1151
+ Object.entries(obj).filter(([_, v]) => v !== void 0 && v !== null && v !== "")
1152
+ );
1153
+ }
1154
+ function stripUndefinedFromArray(arr) {
1155
+ return arr.map(stripUndefined);
1156
+ }
1157
+
1158
+ // src/tools/get-visible-elements.tool.ts
1159
+ var getVisibleElementsToolDefinition = {
1160
+ name: "get_visible_elements",
1161
+ 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',
1162
+ inputSchema: {
1163
+ inViewportOnly: z10.boolean().optional().describe(
1164
+ "Only return elements within the visible viewport. Default: true. Set to false to get ALL elements on the page."
1165
+ ),
1166
+ includeContainers: z10.boolean().optional().describe(
1167
+ "Include layout containers (ViewGroup, FrameLayout, ScrollView, etc). Default: false. Set to true to see all elements including layouts."
1168
+ ),
1169
+ elementType: z10.enum(["interactable", "visual", "all"]).optional().describe(
1170
+ 'Type of elements to return: "interactable" (default) for buttons/links/inputs, "visual" for images/SVGs, "all" for both.'
1171
+ ),
1172
+ limit: z10.number().optional().describe(
1173
+ "Maximum number of elements to return. Default: 0 (unlimited). Set a limit for pages with many elements."
1174
+ )
1175
+ }
1066
1176
  };
1067
1177
  var getVisibleElementsTool = async (args) => {
1068
1178
  try {
1069
1179
  const browser = getBrowser();
1070
- const { inViewportOnly = true, includeContainers = false } = args || {};
1180
+ const {
1181
+ inViewportOnly = true,
1182
+ includeContainers = false,
1183
+ elementType = "interactable",
1184
+ limit = 0
1185
+ } = args || {};
1071
1186
  if (browser.isAndroid || browser.isIOS) {
1072
1187
  const platform = browser.isAndroid ? "android" : "ios";
1073
1188
  let elements2 = await getMobileVisibleElements(browser, platform, {
@@ -1076,19 +1191,23 @@ var getVisibleElementsTool = async (args) => {
1076
1191
  if (inViewportOnly) {
1077
1192
  elements2 = elements2.filter((el) => el.isInViewport);
1078
1193
  }
1194
+ if (limit > 0 && elements2.length > limit) {
1195
+ elements2 = elements2.slice(0, limit);
1196
+ }
1079
1197
  return {
1080
1198
  content: [{ type: "text", text: encode(elements2) }]
1081
1199
  };
1082
1200
  }
1083
- const elements = await browser.execute(get_interactable_elements_default);
1201
+ let elements = await browser.execute(get_interactable_elements_default, elementType);
1084
1202
  if (inViewportOnly) {
1085
- const filteredElements = elements.filter((el) => el.isInViewport !== false);
1086
- return {
1087
- content: [{ type: "text", text: encode(filteredElements) }]
1088
- };
1203
+ elements = elements.filter((el) => el.isInViewport !== false);
1089
1204
  }
1205
+ if (limit > 0 && elements.length > limit) {
1206
+ elements = elements.slice(0, limit);
1207
+ }
1208
+ const cleanedElements = stripUndefinedFromArray(elements);
1090
1209
  return {
1091
- content: [{ type: "text", text: encode(elements) }]
1210
+ content: [{ type: "text", text: encode(cleanedElements) }]
1092
1211
  };
1093
1212
  } catch (e) {
1094
1213
  return {
@@ -1099,8 +1218,12 @@ var getVisibleElementsTool = async (args) => {
1099
1218
 
1100
1219
  // src/tools/take-screenshot.tool.ts
1101
1220
  import { z as z11 } from "zod";
1102
- var takeScreenshotToolArguments = {
1103
- outputPath: z11.string().optional().describe("Optional path where to save the screenshot. If not provided, returns base64 data.")
1221
+ var takeScreenshotToolDefinition = {
1222
+ name: "take_screenshot",
1223
+ description: "captures a screenshot of the current page",
1224
+ inputSchema: {
1225
+ outputPath: z11.string().optional().describe("Optional path where to save the screenshot. If not provided, returns base64 data.")
1226
+ }
1104
1227
  };
1105
1228
  var takeScreenshotTool = async ({ outputPath }) => {
1106
1229
  try {
@@ -1128,8 +1251,12 @@ var takeScreenshotTool = async ({ outputPath }) => {
1128
1251
 
1129
1252
  // src/tools/cookies.tool.ts
1130
1253
  import { z as z12 } from "zod";
1131
- var getCookiesToolArguments = {
1132
- name: z12.string().optional().describe("Optional cookie name to retrieve a specific cookie. If not provided, returns all cookies")
1254
+ var getCookiesToolDefinition = {
1255
+ name: "get_cookies",
1256
+ description: "gets all cookies or a specific cookie by name",
1257
+ inputSchema: {
1258
+ name: z12.string().optional().describe("Optional cookie name to retrieve a specific cookie. If not provided, returns all cookies")
1259
+ }
1133
1260
  };
1134
1261
  var getCookiesTool = async ({ name }) => {
1135
1262
  try {
@@ -1160,15 +1287,19 @@ var getCookiesTool = async ({ name }) => {
1160
1287
  };
1161
1288
  }
1162
1289
  };
1163
- var setCookieToolArguments = {
1164
- name: z12.string().describe("Cookie name"),
1165
- value: z12.string().describe("Cookie value"),
1166
- domain: z12.string().optional().describe("Cookie domain (defaults to current domain)"),
1167
- path: z12.string().optional().describe('Cookie path (defaults to "/")'),
1168
- expires: z12.number().optional().describe("Expiry date as Unix timestamp in seconds"),
1169
- httpOnly: z12.boolean().optional().describe("HttpOnly flag"),
1170
- secure: z12.boolean().optional().describe("Secure flag"),
1171
- sameSite: z12.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute")
1290
+ var setCookieToolDefinition = {
1291
+ name: "set_cookie",
1292
+ description: "sets a cookie with specified name, value, and optional attributes",
1293
+ inputSchema: {
1294
+ name: z12.string().describe("Cookie name"),
1295
+ value: z12.string().describe("Cookie value"),
1296
+ domain: z12.string().optional().describe("Cookie domain (defaults to current domain)"),
1297
+ path: z12.string().optional().describe('Cookie path (defaults to "/")'),
1298
+ expires: z12.number().optional().describe("Expiry date as Unix timestamp in seconds"),
1299
+ httpOnly: z12.boolean().optional().describe("HttpOnly flag"),
1300
+ secure: z12.boolean().optional().describe("Secure flag"),
1301
+ sameSite: z12.enum(["Strict", "Lax", "None"]).optional().describe("SameSite attribute")
1302
+ }
1172
1303
  };
1173
1304
  var setCookieTool = async ({
1174
1305
  name,
@@ -1202,8 +1333,12 @@ var setCookieTool = async ({
1202
1333
  };
1203
1334
  }
1204
1335
  };
1205
- var deleteCookiesToolArguments = {
1206
- name: z12.string().optional().describe("Optional cookie name to delete a specific cookie. If not provided, deletes all cookies")
1336
+ var deleteCookiesToolDefinition = {
1337
+ name: "delete_cookies",
1338
+ description: "deletes all cookies or a specific cookie by name",
1339
+ inputSchema: {
1340
+ name: z12.string().optional().describe("Optional cookie name to delete a specific cookie. If not provided, deletes all cookies")
1341
+ }
1207
1342
  };
1208
1343
  var deleteCookiesTool = async ({ name }) => {
1209
1344
  try {
@@ -1227,36 +1362,46 @@ var deleteCookiesTool = async ({ name }) => {
1227
1362
 
1228
1363
  // src/tools/get-accessibility-tree.tool.ts
1229
1364
  import { encode as encode2 } from "@toon-format/toon";
1365
+ import { z as z13 } from "zod";
1366
+ var getAccessibilityToolDefinition = {
1367
+ name: "get_accessibility",
1368
+ 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.",
1369
+ inputSchema: {
1370
+ limit: z13.number().optional().describe("Maximum number of nodes to return. Default: 100. Use 0 for unlimited."),
1371
+ roles: z13.array(z13.string()).optional().describe('Filter to specific roles (e.g., ["button", "link", "textbox"]). Default: all roles.'),
1372
+ namedOnly: z13.boolean().optional().describe("Only return nodes with a name/label. Default: true. Filters out anonymous containers.")
1373
+ }
1374
+ };
1230
1375
  function flattenAccessibilityTree(node, result = []) {
1231
1376
  if (!node) return result;
1232
1377
  if (node.role !== "WebArea" || node.name) {
1233
- result.push({
1234
- role: node.role,
1235
- name: node.name,
1236
- value: node.value,
1237
- description: node.description,
1238
- keyshortcuts: node.keyshortcuts,
1239
- roledescription: node.roledescription,
1240
- valuetext: node.valuetext,
1241
- disabled: node.disabled,
1242
- expanded: node.expanded,
1243
- focused: node.focused,
1244
- modal: node.modal,
1245
- multiline: node.multiline,
1246
- multiselectable: node.multiselectable,
1247
- readonly: node.readonly,
1248
- required: node.required,
1249
- selected: node.selected,
1250
- checked: node.checked,
1251
- pressed: node.pressed,
1252
- level: node.level,
1253
- valuemin: node.valuemin,
1254
- valuemax: node.valuemax,
1255
- autocomplete: node.autocomplete,
1256
- haspopup: node.haspopup,
1257
- invalid: node.invalid,
1258
- orientation: node.orientation
1259
- });
1378
+ const entry = {};
1379
+ if (node.role) entry.role = node.role;
1380
+ if (node.name) entry.name = node.name;
1381
+ if (node.value !== void 0 && node.value !== "") entry.value = node.value;
1382
+ if (node.description) entry.description = node.description;
1383
+ if (node.keyshortcuts) entry.keyshortcuts = node.keyshortcuts;
1384
+ if (node.roledescription) entry.roledescription = node.roledescription;
1385
+ if (node.valuetext) entry.valuetext = node.valuetext;
1386
+ if (node.disabled) entry.disabled = node.disabled;
1387
+ if (node.expanded !== void 0) entry.expanded = node.expanded;
1388
+ if (node.focused) entry.focused = node.focused;
1389
+ if (node.modal) entry.modal = node.modal;
1390
+ if (node.multiline) entry.multiline = node.multiline;
1391
+ if (node.multiselectable) entry.multiselectable = node.multiselectable;
1392
+ if (node.readonly) entry.readonly = node.readonly;
1393
+ if (node.required) entry.required = node.required;
1394
+ if (node.selected) entry.selected = node.selected;
1395
+ if (node.checked !== void 0) entry.checked = node.checked;
1396
+ if (node.pressed !== void 0) entry.pressed = node.pressed;
1397
+ if (node.level !== void 0) entry.level = node.level;
1398
+ if (node.valuemin !== void 0) entry.valuemin = node.valuemin;
1399
+ if (node.valuemax !== void 0) entry.valuemax = node.valuemax;
1400
+ if (node.autocomplete) entry.autocomplete = node.autocomplete;
1401
+ if (node.haspopup) entry.haspopup = node.haspopup;
1402
+ if (node.invalid) entry.invalid = node.invalid;
1403
+ if (node.orientation) entry.orientation = node.orientation;
1404
+ result.push(entry);
1260
1405
  }
1261
1406
  if (node.children && Array.isArray(node.children)) {
1262
1407
  for (const child of node.children) {
@@ -1265,9 +1410,18 @@ function flattenAccessibilityTree(node, result = []) {
1265
1410
  }
1266
1411
  return result;
1267
1412
  }
1268
- var getAccessibilityTreeTool = async () => {
1413
+ var getAccessibilityTreeTool = async (args) => {
1269
1414
  try {
1270
1415
  const browser = getBrowser();
1416
+ if (browser.isAndroid || browser.isIOS) {
1417
+ return {
1418
+ content: [{
1419
+ type: "text",
1420
+ text: "Error: get_accessibility is browser-only. For mobile apps, use get_visible_elements instead."
1421
+ }]
1422
+ };
1423
+ }
1424
+ const { limit = 100, roles, namedOnly = true } = args || {};
1271
1425
  const puppeteer = await browser.getPuppeteer();
1272
1426
  const pages = await puppeteer.pages();
1273
1427
  if (pages.length === 0) {
@@ -1285,11 +1439,21 @@ var getAccessibilityTreeTool = async () => {
1285
1439
  content: [{ type: "text", text: "No accessibility tree available" }]
1286
1440
  };
1287
1441
  }
1288
- const flattenedNodes = flattenAccessibilityTree(snapshot);
1442
+ let nodes = flattenAccessibilityTree(snapshot);
1443
+ if (namedOnly) {
1444
+ nodes = nodes.filter((n) => n.name && n.name.trim() !== "");
1445
+ }
1446
+ if (roles && roles.length > 0) {
1447
+ const roleSet = new Set(roles.map((r) => r.toLowerCase()));
1448
+ nodes = nodes.filter((n) => n.role && roleSet.has(n.role.toLowerCase()));
1449
+ }
1450
+ if (limit > 0 && nodes.length > limit) {
1451
+ nodes = nodes.slice(0, limit);
1452
+ }
1289
1453
  return {
1290
1454
  content: [{
1291
1455
  type: "text",
1292
- text: encode2(flattenedNodes)
1456
+ text: encode2(nodes)
1293
1457
  }]
1294
1458
  };
1295
1459
  } catch (e) {
@@ -1301,7 +1465,7 @@ var getAccessibilityTreeTool = async () => {
1301
1465
 
1302
1466
  // src/tools/app-session.tool.ts
1303
1467
  import { remote as remote2 } from "webdriverio";
1304
- import { z as z13 } from "zod";
1468
+ import { z as z14 } from "zod";
1305
1469
 
1306
1470
  // src/config/appium.config.ts
1307
1471
  function getAppiumServerConfig(overrides) {
@@ -1381,22 +1545,26 @@ function buildAndroidCapabilities(appPath, options) {
1381
1545
  }
1382
1546
 
1383
1547
  // src/tools/app-session.tool.ts
1384
- var startAppToolArguments = {
1385
- platform: z13.enum(["iOS", "Android"]).describe("Mobile platform"),
1386
- appPath: z13.string().optional().describe("Path to the app file (.app/.apk/.ipa). Required unless noReset=true (connecting to already-running app)"),
1387
- deviceName: z13.string().describe("Device/emulator/simulator name"),
1388
- platformVersion: z13.string().optional().describe('OS version (e.g., "17.0", "14")'),
1389
- automationName: z13.enum(["XCUITest", "UiAutomator2", "Espresso"]).optional().describe("Automation driver name"),
1390
- appiumHost: z13.string().optional().describe("Appium server hostname (overrides APPIUM_URL env var)"),
1391
- appiumPort: z13.number().optional().describe("Appium server port (overrides APPIUM_URL_PORT env var)"),
1392
- appiumPath: z13.string().optional().describe("Appium server path (overrides APPIUM_PATH env var)"),
1393
- autoGrantPermissions: z13.boolean().optional().describe("Auto-grant app permissions (default: true)"),
1394
- autoAcceptAlerts: z13.boolean().optional().describe("Auto-accept alerts (default: true)"),
1395
- autoDismissAlerts: z13.boolean().optional().describe('Auto-dismiss alerts (default: false, will override "autoAcceptAlerts" to undefined if set)'),
1396
- appWaitActivity: z13.string().optional().describe("Activity to wait for on launch (Android only)"),
1397
- udid: z13.string().optional().describe('Unique Device Identifier for iOS real device testing (e.g., "00008030-001234567890002E")'),
1398
- noReset: z13.boolean().optional().describe("Do not reset app state before session (preserves app data). Default: false"),
1399
- fullReset: z13.boolean().optional().describe("Uninstall app before/after session. Default: true. Set to false with noReset=true to preserve app state completely")
1548
+ var startAppToolDefinition = {
1549
+ name: "start_app_session",
1550
+ description: "starts a mobile app session (iOS/Android) via Appium",
1551
+ inputSchema: {
1552
+ platform: z14.enum(["iOS", "Android"]).describe("Mobile platform"),
1553
+ appPath: z14.string().optional().describe("Path to the app file (.app/.apk/.ipa). Required unless noReset=true (connecting to already-running app)"),
1554
+ deviceName: z14.string().describe("Device/emulator/simulator name"),
1555
+ platformVersion: z14.string().optional().describe('OS version (e.g., "17.0", "14")'),
1556
+ automationName: z14.enum(["XCUITest", "UiAutomator2", "Espresso"]).optional().describe("Automation driver name"),
1557
+ appiumHost: z14.string().optional().describe("Appium server hostname (overrides APPIUM_URL env var)"),
1558
+ appiumPort: z14.number().optional().describe("Appium server port (overrides APPIUM_URL_PORT env var)"),
1559
+ appiumPath: z14.string().optional().describe("Appium server path (overrides APPIUM_PATH env var)"),
1560
+ autoGrantPermissions: z14.boolean().optional().describe("Auto-grant app permissions (default: true)"),
1561
+ autoAcceptAlerts: z14.boolean().optional().describe("Auto-accept alerts (default: true)"),
1562
+ autoDismissAlerts: z14.boolean().optional().describe('Auto-dismiss alerts (default: false, will override "autoAcceptAlerts" to undefined if set)'),
1563
+ appWaitActivity: z14.string().optional().describe("Activity to wait for on launch (Android only)"),
1564
+ udid: z14.string().optional().describe('Unique Device Identifier for iOS real device testing (e.g., "00008030-001234567890002E")'),
1565
+ noReset: z14.boolean().optional().describe("Do not reset app state before session (preserves app data). Default: false"),
1566
+ fullReset: z14.boolean().optional().describe("Uninstall app before/after session. Default: true. Set to false with noReset=true to preserve app state completely")
1567
+ }
1400
1568
  };
1401
1569
  var getState = () => {
1402
1570
  const sharedState = getBrowser.__state;
@@ -1496,11 +1664,15 @@ Appium Server: ${serverConfig.hostname}:${serverConfig.port}${serverConfig.path}
1496
1664
  };
1497
1665
 
1498
1666
  // src/tools/gestures.tool.ts
1499
- import { z as z14 } from "zod";
1500
- var tapElementToolArguments = {
1501
- selector: z14.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1502
- x: z14.number().optional().describe("X coordinate for tap (if no selector provided)"),
1503
- y: z14.number().optional().describe("Y coordinate for tap (if no selector provided)")
1667
+ import { z as z15 } from "zod";
1668
+ var tapElementToolDefinition = {
1669
+ name: "tap_element",
1670
+ description: "taps an element by selector or coordinates (mobile)",
1671
+ inputSchema: {
1672
+ selector: z15.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1673
+ x: z15.number().optional().describe("X coordinate for tap (if no selector provided)"),
1674
+ y: z15.number().optional().describe("Y coordinate for tap (if no selector provided)")
1675
+ }
1504
1676
  };
1505
1677
  var tapElementTool = async (args) => {
1506
1678
  try {
@@ -1531,12 +1703,16 @@ var tapElementTool = async (args) => {
1531
1703
  };
1532
1704
  }
1533
1705
  };
1534
- var swipeToolArguments = {
1535
- direction: z14.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
1536
- duration: z14.number().min(100).max(5e3).optional().describe("Swipe duration in milliseconds (default: 500)"),
1537
- startX: z14.number().optional().describe("Start X coordinate (optional, uses screen center)"),
1538
- startY: z14.number().optional().describe("Start Y coordinate (optional, uses screen center)"),
1539
- distance: z14.number().optional().describe("Swipe distance in pixels (optional, uses percentage of screen)")
1706
+ var swipeToolDefinition = {
1707
+ name: "swipe",
1708
+ description: "performs a swipe gesture in specified direction (mobile)",
1709
+ inputSchema: {
1710
+ direction: z15.enum(["up", "down", "left", "right"]).describe("Swipe direction"),
1711
+ duration: z15.number().min(100).max(5e3).optional().describe("Swipe duration in milliseconds (default: 500)"),
1712
+ startX: z15.number().optional().describe("Start X coordinate (optional, uses screen center)"),
1713
+ startY: z15.number().optional().describe("Start Y coordinate (optional, uses screen center)"),
1714
+ distance: z15.number().optional().describe("Swipe distance in pixels (optional, uses percentage of screen)")
1715
+ }
1540
1716
  };
1541
1717
  var swipeTool = async (args) => {
1542
1718
  try {
@@ -1584,11 +1760,15 @@ var swipeTool = async (args) => {
1584
1760
  };
1585
1761
  }
1586
1762
  };
1587
- var longPressToolArguments = {
1588
- selector: z14.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1589
- x: z14.number().optional().describe("X coordinate for long press (if no selector provided)"),
1590
- y: z14.number().optional().describe("Y coordinate for long press (if no selector provided)"),
1591
- duration: z14.number().min(500).max(1e4).optional().describe("Long press duration in milliseconds (default: 1000)")
1763
+ var longPressToolDefinition = {
1764
+ name: "long_press",
1765
+ description: "performs a long press on element or coordinates (mobile)",
1766
+ inputSchema: {
1767
+ selector: z15.string().optional().describe("Element selector (CSS, XPath, accessibility ID, or UiAutomator)"),
1768
+ x: z15.number().optional().describe("X coordinate for long press (if no selector provided)"),
1769
+ y: z15.number().optional().describe("Y coordinate for long press (if no selector provided)"),
1770
+ duration: z15.number().min(500).max(1e4).optional().describe("Long press duration in milliseconds (default: 1000)")
1771
+ }
1592
1772
  };
1593
1773
  var longPressTool = async (args) => {
1594
1774
  try {
@@ -1623,14 +1803,18 @@ var longPressTool = async (args) => {
1623
1803
  };
1624
1804
  }
1625
1805
  };
1626
- var dragAndDropToolArguments = {
1627
- fromSelector: z14.string().optional().describe("Source element selector"),
1628
- fromX: z14.number().optional().describe("Source X coordinate"),
1629
- fromY: z14.number().optional().describe("Source Y coordinate"),
1630
- toSelector: z14.string().optional().describe("Target element selector"),
1631
- toX: z14.number().optional().describe("Target X coordinate"),
1632
- toY: z14.number().optional().describe("Target Y coordinate"),
1633
- duration: z14.number().min(100).max(5e3).optional().describe("Drag duration in milliseconds (default: 500)")
1806
+ var dragAndDropToolDefinition = {
1807
+ name: "drag_and_drop",
1808
+ description: "drags from one location to another (mobile)",
1809
+ inputSchema: {
1810
+ fromSelector: z15.string().optional().describe("Source element selector"),
1811
+ fromX: z15.number().optional().describe("Source X coordinate"),
1812
+ fromY: z15.number().optional().describe("Source Y coordinate"),
1813
+ toSelector: z15.string().optional().describe("Target element selector"),
1814
+ toX: z15.number().optional().describe("Target X coordinate"),
1815
+ toY: z15.number().optional().describe("Target Y coordinate"),
1816
+ duration: z15.number().min(100).max(5e3).optional().describe("Drag duration in milliseconds (default: 500)")
1817
+ }
1634
1818
  };
1635
1819
  var dragAndDropTool = async (args) => {
1636
1820
  try {
@@ -1690,9 +1874,13 @@ var dragAndDropTool = async (args) => {
1690
1874
  };
1691
1875
 
1692
1876
  // src/tools/app-actions.tool.ts
1693
- import { z as z15 } from "zod";
1694
- var getAppStateToolArguments = {
1695
- bundleId: z15.string().describe("App bundle ID (e.g., com.example.app)")
1877
+ import { z as z16 } from "zod";
1878
+ var getAppStateToolDefinition = {
1879
+ name: "get_app_state",
1880
+ description: "gets the state of an app (not installed, not running, background, foreground)",
1881
+ inputSchema: {
1882
+ bundleId: z16.string().describe("App bundle ID (e.g., com.example.app)")
1883
+ }
1696
1884
  };
1697
1885
  var getAppStateTool = async (args) => {
1698
1886
  try {
@@ -1721,8 +1909,12 @@ var getAppStateTool = async (args) => {
1721
1909
  };
1722
1910
  }
1723
1911
  };
1724
- var activateAppToolArguments = {
1725
- bundleId: z15.string().describe("App bundle ID to activate (e.g., com.example.app)")
1912
+ var activateAppToolDefinition = {
1913
+ name: "activate_app",
1914
+ description: "activates/brings an app to foreground",
1915
+ inputSchema: {
1916
+ bundleId: z16.string().describe("App bundle ID to activate (e.g., com.example.app)")
1917
+ }
1726
1918
  };
1727
1919
  var activateAppTool = async (args) => {
1728
1920
  try {
@@ -1739,8 +1931,12 @@ var activateAppTool = async (args) => {
1739
1931
  };
1740
1932
  }
1741
1933
  };
1742
- var terminateAppToolArguments = {
1743
- bundleId: z15.string().describe("App bundle ID to terminate (e.g., com.example.app)")
1934
+ var terminateAppToolDefinition = {
1935
+ name: "terminate_app",
1936
+ description: "terminates a running app",
1937
+ inputSchema: {
1938
+ bundleId: z16.string().describe("App bundle ID to terminate (e.g., com.example.app)")
1939
+ }
1744
1940
  };
1745
1941
  var terminateAppTool = async (args) => {
1746
1942
  try {
@@ -1759,7 +1955,26 @@ var terminateAppTool = async (args) => {
1759
1955
  };
1760
1956
 
1761
1957
  // src/tools/context.tool.ts
1762
- import { z as z16 } from "zod";
1958
+ import { z as z17 } from "zod";
1959
+ var getContextsToolDefinition = {
1960
+ name: "get_contexts",
1961
+ description: "lists available contexts (NATIVE_APP, WEBVIEW)",
1962
+ inputSchema: {}
1963
+ };
1964
+ var getCurrentContextToolDefinition = {
1965
+ name: "get_current_context",
1966
+ description: "shows the currently active context",
1967
+ inputSchema: {}
1968
+ };
1969
+ var switchContextToolDefinition = {
1970
+ name: "switch_context",
1971
+ description: "switches between native and webview contexts",
1972
+ inputSchema: {
1973
+ context: z17.string().describe(
1974
+ 'Context name to switch to (e.g., "NATIVE_APP", "WEBVIEW_com.example.app", or use index from get_contexts)'
1975
+ )
1976
+ }
1977
+ };
1763
1978
  var getContextsTool = async () => {
1764
1979
  try {
1765
1980
  const browser = getBrowser();
@@ -1792,11 +2007,6 @@ var getCurrentContextTool = async () => {
1792
2007
  };
1793
2008
  }
1794
2009
  };
1795
- var switchContextToolArguments = {
1796
- context: z16.string().describe(
1797
- 'Context name to switch to (e.g., "NATIVE_APP", "WEBVIEW_com.example.app", or use index from get_contexts)'
1798
- )
1799
- };
1800
2010
  var switchContextTool = async (args) => {
1801
2011
  try {
1802
2012
  const browser = getBrowser();
@@ -1830,7 +2040,87 @@ var switchContextTool = async (args) => {
1830
2040
  };
1831
2041
 
1832
2042
  // src/tools/device.tool.ts
1833
- import { z as z17 } from "zod";
2043
+ import { z as z18 } from "zod";
2044
+ var getDeviceInfoToolDefinition = {
2045
+ name: "get_device_info",
2046
+ description: "gets device information (platform, version, screen size)",
2047
+ inputSchema: {}
2048
+ };
2049
+ var getOrientationToolDefinition = {
2050
+ name: "get_orientation",
2051
+ description: "gets current device orientation",
2052
+ inputSchema: {}
2053
+ };
2054
+ var lockDeviceToolDefinition = {
2055
+ name: "lock_device",
2056
+ description: "locks the device screen",
2057
+ inputSchema: {}
2058
+ };
2059
+ var unlockDeviceToolDefinition = {
2060
+ name: "unlock_device",
2061
+ description: "unlocks the device screen",
2062
+ inputSchema: {}
2063
+ };
2064
+ var isDeviceLockedToolDefinition = {
2065
+ name: "is_device_locked",
2066
+ description: "checks if device is locked",
2067
+ inputSchema: {}
2068
+ };
2069
+ var shakeDeviceToolDefinition = {
2070
+ name: "shake_device",
2071
+ description: "shakes the device (iOS only)",
2072
+ inputSchema: {}
2073
+ };
2074
+ var hideKeyboardToolDefinition = {
2075
+ name: "hide_keyboard",
2076
+ description: "hides the on-screen keyboard",
2077
+ inputSchema: {}
2078
+ };
2079
+ var isKeyboardShownToolDefinition = {
2080
+ name: "is_keyboard_shown",
2081
+ description: "checks if keyboard is visible",
2082
+ inputSchema: {}
2083
+ };
2084
+ var openNotificationsToolDefinition = {
2085
+ name: "open_notifications",
2086
+ description: "opens the notifications panel (Android only)",
2087
+ inputSchema: {}
2088
+ };
2089
+ var getGeolocationToolDefinition = {
2090
+ name: "get_geolocation",
2091
+ description: "gets current device geolocation",
2092
+ inputSchema: {}
2093
+ };
2094
+ var rotateDeviceToolDefinition = {
2095
+ name: "rotate_device",
2096
+ description: "rotates device to portrait or landscape orientation",
2097
+ inputSchema: {
2098
+ orientation: z18.enum(["PORTRAIT", "LANDSCAPE"]).describe("Device orientation")
2099
+ }
2100
+ };
2101
+ var sendKeysToolDefinition = {
2102
+ name: "send_keys",
2103
+ description: "sends keys to the app (Android only)",
2104
+ inputSchema: {
2105
+ keys: z18.array(z18.string()).describe('Array of keys to send (e.g., ["h", "e", "l", "l", "o"])')
2106
+ }
2107
+ };
2108
+ var pressKeyCodeToolDefinition = {
2109
+ name: "press_key_code",
2110
+ description: "presses an Android key code (Android only)",
2111
+ inputSchema: {
2112
+ keyCode: z18.number().describe("Android key code (e.g., 4 for BACK, 3 for HOME)")
2113
+ }
2114
+ };
2115
+ var setGeolocationToolDefinition = {
2116
+ name: "set_geolocation",
2117
+ description: "sets device geolocation (latitude, longitude, altitude)",
2118
+ inputSchema: {
2119
+ latitude: z18.number().min(-90).max(90).describe("Latitude coordinate"),
2120
+ longitude: z18.number().min(-180).max(180).describe("Longitude coordinate"),
2121
+ altitude: z18.number().optional().describe("Altitude in meters (optional)")
2122
+ }
2123
+ };
1834
2124
  var getDeviceInfoTool = async () => {
1835
2125
  try {
1836
2126
  const browser = getBrowser();
@@ -1858,9 +2148,6 @@ ${Object.entries(info).map(([key, value]) => ` ${key}: ${value}`).join("\n")}`
1858
2148
  };
1859
2149
  }
1860
2150
  };
1861
- var rotateDeviceToolArguments = {
1862
- orientation: z17.enum(["PORTRAIT", "LANDSCAPE"]).describe("Device orientation")
1863
- };
1864
2151
  var rotateDeviceTool = async (args) => {
1865
2152
  try {
1866
2153
  const browser = getBrowser();
@@ -1940,9 +2227,6 @@ var shakeDeviceTool = async () => {
1940
2227
  };
1941
2228
  }
1942
2229
  };
1943
- var sendKeysToolArguments = {
1944
- keys: z17.array(z17.string()).describe('Array of keys to send (e.g., ["h", "e", "l", "l", "o"])')
1945
- };
1946
2230
  var sendKeysTool = async (args) => {
1947
2231
  try {
1948
2232
  const browser = getBrowser();
@@ -1957,9 +2241,6 @@ var sendKeysTool = async (args) => {
1957
2241
  };
1958
2242
  }
1959
2243
  };
1960
- var pressKeyCodeToolArguments = {
1961
- keyCode: z17.number().describe("Android key code (e.g., 4 for BACK, 3 for HOME)")
1962
- };
1963
2244
  var pressKeyCodeTool = async (args) => {
1964
2245
  try {
1965
2246
  const browser = getBrowser();
@@ -2034,11 +2315,6 @@ var getGeolocationTool = async () => {
2034
2315
  };
2035
2316
  }
2036
2317
  };
2037
- var setGeolocationToolArguments = {
2038
- latitude: z17.number().min(-90).max(90).describe("Latitude coordinate"),
2039
- longitude: z17.number().min(-180).max(180).describe("Longitude coordinate"),
2040
- altitude: z17.number().optional().describe("Altitude in meters (optional)")
2041
- };
2042
2318
  var setGeolocationTool = async (args) => {
2043
2319
  try {
2044
2320
  const browser = getBrowser();
@@ -2062,62 +2338,129 @@ var setGeolocationTool = async (args) => {
2062
2338
  }
2063
2339
  };
2064
2340
 
2341
+ // package.json
2342
+ var package_default = {
2343
+ name: "@wdio/mcp",
2344
+ author: "Vince Graics",
2345
+ repository: {
2346
+ type: "git",
2347
+ url: "git://github.com/webdriverio/mcp.git"
2348
+ },
2349
+ version: "1.5.0",
2350
+ description: "MCP server with WebdriverIO for browser and mobile app automation (iOS/Android via Appium)",
2351
+ main: "./lib/server.js",
2352
+ module: "./lib/server.js",
2353
+ types: "./lib/server.d.ts",
2354
+ bin: {
2355
+ "wdio-mcp": "lib/server.js"
2356
+ },
2357
+ license: "MIT",
2358
+ publishConfig: {
2359
+ access: "public"
2360
+ },
2361
+ type: "module",
2362
+ files: [
2363
+ "lib",
2364
+ "README.md"
2365
+ ],
2366
+ scripts: {
2367
+ prebundle: "rimraf lib --glob ./*.tgz",
2368
+ bundle: "tsup && shx chmod +x lib/server.js",
2369
+ postbundle: "npm pack",
2370
+ lint: "eslint src/ --fix && tsc --noEmit",
2371
+ start: "node lib/server.js",
2372
+ dev: "tsx --watch src/server.ts",
2373
+ prepare: "husky"
2374
+ },
2375
+ dependencies: {
2376
+ "@modelcontextprotocol/sdk": "1.25",
2377
+ "@toon-format/toon": "^2.1.0",
2378
+ "@wdio/protocols": "^9.16.2",
2379
+ "@xmldom/xmldom": "^0.8.11",
2380
+ "puppeteer-core": "^24.35.0",
2381
+ webdriverio: "9.22",
2382
+ zod: "^4.3.5"
2383
+ },
2384
+ devDependencies: {
2385
+ "@release-it/conventional-changelog": "^10.0.4",
2386
+ "@types/node": "^20.11.0",
2387
+ "@wdio/eslint": "^0.1.3",
2388
+ "@wdio/types": "^9.20.0",
2389
+ eslint: "^9.39.2",
2390
+ husky: "^9.1.7",
2391
+ "release-it": "^19.2.3",
2392
+ rimraf: "^6.1.2",
2393
+ shx: "^0.4.0",
2394
+ tsup: "^8.5.1",
2395
+ tsx: "^4.21.0",
2396
+ typescript: "5.9"
2397
+ },
2398
+ packageManager: "pnpm@10.12.4"
2399
+ };
2400
+
2065
2401
  // src/server.ts
2066
2402
  console.log = (...args) => console.error("[LOG]", ...args);
2067
2403
  console.info = (...args) => console.error("[INFO]", ...args);
2068
2404
  console.warn = (...args) => console.error("[WARN]", ...args);
2069
2405
  console.debug = (...args) => console.error("[DEBUG]", ...args);
2070
2406
  var server = new McpServer({
2071
- name: "MCP WebdriverIO",
2072
- version: "1.4.0"
2407
+ title: "WebdriverIO MCP Server",
2408
+ name: package_default.name,
2409
+ version: package_default.version,
2410
+ description: package_default.description,
2411
+ websiteUrl: "https://github.com/webdriverio/mcp"
2073
2412
  }, {
2413
+ 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.",
2074
2414
  capabilities: {
2075
- resources: {},
2076
2415
  tools: {}
2077
2416
  }
2078
2417
  });
2079
- server.tool("start_browser", "starts a browser session and sets it to the current state", startBrowserToolArguments, startBrowserTool);
2080
- server.tool("start_app_session", "starts a mobile app session (iOS/Android) via Appium", startAppToolArguments, startAppTool);
2081
- server.tool("close_session", "closes or detaches from the current browser or app session", closeSessionToolArguments, closeSessionTool);
2082
- server.tool("navigate", "navigates to a URL", navigateToolArguments, navigateTool);
2083
- server.tool("get_visible_elements", "get a list of visible (in viewport & displayed) elements on the page, must prefer this to take_screenshot for interactions", getVisibleElementsToolArguments, getVisibleElementsTool);
2084
- server.tool("get_accessibility", "gets accessibility tree snapshot with semantic information about page elements (roles, names, states)", {}, getAccessibilityTreeTool);
2085
- server.tool("scroll_down", "scrolls the page down by specified pixels", scrollDownToolArguments, scrollDownTool);
2086
- server.tool("scroll_up", "scrolls the page up by specified pixels", scrollUpToolArguments, scrollUpTool);
2087
- server.tool("find_element", "finds an element", findElementToolArguments, findElementTool);
2088
- server.tool("click_element", "clicks an element", clickToolArguments, clickTool);
2089
- server.tool("click_via_text", "clicks an element", clickToolArguments, clickToolViaText);
2090
- server.tool("set_value", "set value to an element, aka typing", setValueToolArguments, setValueTool);
2091
- server.tool("get_element_text", "gets the text content of an element", getElementTextToolArguments, getElementTextTool);
2092
- server.tool("is_displayed", "checks if an element is displayed", isDisplayedToolArguments, isDisplayedTool);
2093
- server.tool("take_screenshot", "captures a screenshot of the current page", takeScreenshotToolArguments, takeScreenshotTool);
2094
- server.tool("get_cookies", "gets all cookies or a specific cookie by name", getCookiesToolArguments, getCookiesTool);
2095
- server.tool("set_cookie", "sets a cookie with specified name, value, and optional attributes", setCookieToolArguments, setCookieTool);
2096
- server.tool("delete_cookies", "deletes all cookies or a specific cookie by name", deleteCookiesToolArguments, deleteCookiesTool);
2097
- server.tool("tap_element", "taps an element by selector or coordinates (mobile)", tapElementToolArguments, tapElementTool);
2098
- server.tool("swipe", "performs a swipe gesture in specified direction (mobile)", swipeToolArguments, swipeTool);
2099
- server.tool("long_press", "performs a long press on element or coordinates (mobile)", longPressToolArguments, longPressTool);
2100
- server.tool("drag_and_drop", "drags from one location to another (mobile)", dragAndDropToolArguments, dragAndDropTool);
2101
- server.tool("get_app_state", "gets the state of an app (not installed, not running, background, foreground)", getAppStateToolArguments, getAppStateTool);
2102
- server.tool("activate_app", "activates/brings an app to foreground", activateAppToolArguments, activateAppTool);
2103
- server.tool("terminate_app", "terminates a running app", terminateAppToolArguments, terminateAppTool);
2104
- server.tool("get_contexts", "lists available contexts (NATIVE_APP, WEBVIEW)", {}, getContextsTool);
2105
- server.tool("get_current_context", "shows the currently active context", {}, getCurrentContextTool);
2106
- server.tool("switch_context", "switches between native and webview contexts", switchContextToolArguments, switchContextTool);
2107
- server.tool("get_device_info", "gets device information (platform, version, screen size)", {}, getDeviceInfoTool);
2108
- server.tool("rotate_device", "rotates device to portrait or landscape orientation", rotateDeviceToolArguments, rotateDeviceTool);
2109
- server.tool("get_orientation", "gets current device orientation", {}, getOrientationTool);
2110
- server.tool("lock_device", "locks the device screen", {}, lockDeviceTool);
2111
- server.tool("unlock_device", "unlocks the device screen", {}, unlockDeviceTool);
2112
- server.tool("is_device_locked", "checks if device is locked", {}, isDeviceLockedTool);
2113
- server.tool("shake_device", "shakes the device (iOS only)", {}, shakeDeviceTool);
2114
- server.tool("send_keys", "sends keys to the app (Android only)", sendKeysToolArguments, sendKeysTool);
2115
- server.tool("press_key_code", "presses an Android key code (Android only)", pressKeyCodeToolArguments, pressKeyCodeTool);
2116
- server.tool("hide_keyboard", "hides the on-screen keyboard", {}, hideKeyboardTool);
2117
- server.tool("is_keyboard_shown", "checks if keyboard is visible", {}, isKeyboardShownTool);
2118
- server.tool("open_notifications", "opens the notifications panel (Android only)", {}, openNotificationsTool);
2119
- server.tool("get_geolocation", "gets current device geolocation", {}, getGeolocationTool);
2120
- server.tool("set_geolocation", "sets device geolocation (latitude, longitude, altitude)", setGeolocationToolArguments, setGeolocationTool);
2418
+ var registerTool = (definition, callback) => server.registerTool(definition.name, {
2419
+ description: definition.description,
2420
+ inputSchema: definition.inputSchema
2421
+ }, callback);
2422
+ registerTool(startBrowserToolDefinition, startBrowserTool);
2423
+ registerTool(startAppToolDefinition, startAppTool);
2424
+ registerTool(closeSessionToolDefinition, closeSessionTool);
2425
+ registerTool(navigateToolDefinition, navigateTool);
2426
+ registerTool(getVisibleElementsToolDefinition, getVisibleElementsTool);
2427
+ registerTool(getAccessibilityToolDefinition, getAccessibilityTreeTool);
2428
+ registerTool(scrollDownToolDefinition, scrollDownTool);
2429
+ registerTool(scrollUpToolDefinition, scrollUpTool);
2430
+ registerTool(findElementToolDefinition, findElementTool);
2431
+ registerTool(clickToolDefinition, clickTool);
2432
+ registerTool(clickViaTextToolDefinition, clickToolViaText);
2433
+ registerTool(setValueToolDefinition, setValueTool);
2434
+ registerTool(getElementTextToolDefinition, getElementTextTool);
2435
+ registerTool(isDisplayedToolDefinition, isDisplayedTool);
2436
+ registerTool(takeScreenshotToolDefinition, takeScreenshotTool);
2437
+ registerTool(getCookiesToolDefinition, getCookiesTool);
2438
+ registerTool(setCookieToolDefinition, setCookieTool);
2439
+ registerTool(deleteCookiesToolDefinition, deleteCookiesTool);
2440
+ registerTool(tapElementToolDefinition, tapElementTool);
2441
+ registerTool(swipeToolDefinition, swipeTool);
2442
+ registerTool(longPressToolDefinition, longPressTool);
2443
+ registerTool(dragAndDropToolDefinition, dragAndDropTool);
2444
+ registerTool(getAppStateToolDefinition, getAppStateTool);
2445
+ registerTool(activateAppToolDefinition, activateAppTool);
2446
+ registerTool(terminateAppToolDefinition, terminateAppTool);
2447
+ registerTool(getContextsToolDefinition, getContextsTool);
2448
+ registerTool(getCurrentContextToolDefinition, getCurrentContextTool);
2449
+ registerTool(switchContextToolDefinition, switchContextTool);
2450
+ registerTool(getDeviceInfoToolDefinition, getDeviceInfoTool);
2451
+ registerTool(rotateDeviceToolDefinition, rotateDeviceTool);
2452
+ registerTool(getOrientationToolDefinition, getOrientationTool);
2453
+ registerTool(lockDeviceToolDefinition, lockDeviceTool);
2454
+ registerTool(unlockDeviceToolDefinition, unlockDeviceTool);
2455
+ registerTool(isDeviceLockedToolDefinition, isDeviceLockedTool);
2456
+ registerTool(shakeDeviceToolDefinition, shakeDeviceTool);
2457
+ registerTool(sendKeysToolDefinition, sendKeysTool);
2458
+ registerTool(pressKeyCodeToolDefinition, pressKeyCodeTool);
2459
+ registerTool(hideKeyboardToolDefinition, hideKeyboardTool);
2460
+ registerTool(isKeyboardShownToolDefinition, isKeyboardShownTool);
2461
+ registerTool(openNotificationsToolDefinition, openNotificationsTool);
2462
+ registerTool(getGeolocationToolDefinition, getGeolocationTool);
2463
+ registerTool(setGeolocationToolDefinition, setGeolocationTool);
2121
2464
  async function main() {
2122
2465
  const transport = new StdioServerTransport();
2123
2466
  await server.connect(transport);