@nbakka/mcp-appium 2.0.9 → 2.0.11
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 +20 -59
- package/package.json +1 -1
package/lib/server.js
CHANGED
|
@@ -214,73 +214,34 @@ await new Promise(resolve => setTimeout(resolve, 5000));
|
|
|
214
214
|
return `Current device orientation is ${orientation}`;
|
|
215
215
|
});
|
|
216
216
|
tool(
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
{
|
|
217
|
+
"mobile_tap_by_text",
|
|
218
|
+
"Tap an element on screen by its displayed text or accessibility label using ADB tap",
|
|
219
|
+
{
|
|
220
|
+
text: zod_1.z.string().describe("The exact text or label of the element to tap"),
|
|
221
|
+
},
|
|
220
222
|
async ({ text }) => {
|
|
221
|
-
const { execSync } = require("child_process");
|
|
222
|
-
const { XMLParser } = require("fast-xml-parser");
|
|
223
|
-
|
|
224
223
|
if (!text) throw new Error("Input text is required");
|
|
225
224
|
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
try {
|
|
229
|
-
dump = execSync("adb shell uiautomator dump /dev/tty", { maxBuffer: 10 * 1024 * 1024 }).toString();
|
|
230
|
-
} catch (e) {
|
|
231
|
-
throw new Error("Failed to dump UI Automator XML via adb");
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// 2. Parse XML
|
|
235
|
-
const parser = new XMLParser({
|
|
236
|
-
ignoreAttributes: false,
|
|
237
|
-
attributeNamePrefix: "",
|
|
238
|
-
});
|
|
239
|
-
const xmlObj = parser.parse(dump);
|
|
240
|
-
|
|
241
|
-
// 3. Recursive traversal to find matching element by text/content-desc/hint
|
|
242
|
-
function findElement(node) {
|
|
243
|
-
if (!node) return null;
|
|
244
|
-
|
|
245
|
-
const matchText = node.text || node["content-desc"] || node.hint || "";
|
|
246
|
-
if (matchText === text) return node;
|
|
225
|
+
requireRobot(); // ensure robot instance available
|
|
226
|
+
const elements = await robot.getElementsOnScreen();
|
|
247
227
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (found) return found;
|
|
253
|
-
}
|
|
254
|
-
} else {
|
|
255
|
-
return findElement(node.node);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return null;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
const element = findElement(xmlObj.hierarchy.node);
|
|
263
|
-
if (!element) throw new Error(`Element with text "${text}" not found`);
|
|
228
|
+
// Find element by exact match on text or label
|
|
229
|
+
const element = elements.find(
|
|
230
|
+
el => el.text === text || el.label === text
|
|
231
|
+
);
|
|
264
232
|
|
|
265
|
-
|
|
266
|
-
const bounds = element.bounds;
|
|
267
|
-
if (!bounds) throw new Error("Element bounds not found");
|
|
233
|
+
if (!element) throw new Error(`Element with text or label "${text}" not found`);
|
|
268
234
|
|
|
269
|
-
|
|
270
|
-
|
|
235
|
+
// Calculate center coordinates
|
|
236
|
+
const rect = element.rect;
|
|
237
|
+
const x = Math.floor(rect.x + rect.width / 2);
|
|
238
|
+
const y = Math.floor(rect.y + rect.height / 2);
|
|
271
239
|
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
// 5. Tap via adb
|
|
277
|
-
try {
|
|
278
|
-
execSync(`adb shell input tap ${x} ${y}`);
|
|
279
|
-
} catch (e) {
|
|
280
|
-
throw new Error("Failed to perform tap via adb");
|
|
281
|
-
}
|
|
240
|
+
// Execute adb tap
|
|
241
|
+
const { execSync } = require("child_process");
|
|
242
|
+
execSync(`adb shell input tap ${x} ${y}`);
|
|
282
243
|
|
|
283
|
-
return `Tapped element with text "${text}" at (${x},${y})`;
|
|
244
|
+
return `Tapped element with text/label "${text}" at (${x},${y})`;
|
|
284
245
|
}
|
|
285
246
|
);
|
|
286
247
|
// async check for latest agent version
|