@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 +567 -224
- package/lib/server.js.map +1 -1
- package/package.json +6 -3
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
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
16
|
-
|
|
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
|
|
99
|
-
|
|
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
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
175
|
-
|
|
176
|
-
|
|
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
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
218
|
-
|
|
219
|
-
|
|
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
|
|
242
|
-
|
|
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
|
|
263
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
389
|
-
tagName:
|
|
390
|
-
|
|
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
|
|
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
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
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 {
|
|
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
|
-
|
|
1201
|
+
let elements = await browser.execute(get_interactable_elements_default, elementType);
|
|
1084
1202
|
if (inViewportOnly) {
|
|
1085
|
-
|
|
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(
|
|
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
|
|
1103
|
-
|
|
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
|
|
1132
|
-
name:
|
|
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
|
|
1164
|
-
name:
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
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
|
|
1206
|
-
name:
|
|
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
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
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
|
|
1500
|
-
var
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
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
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
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
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
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
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
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
|
|
1694
|
-
var
|
|
1695
|
-
|
|
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
|
|
1725
|
-
|
|
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
|
|
1743
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
2072
|
-
|
|
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
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
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);
|