@nbakka/mcp-appium 4.0.1 → 4.0.3
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 +43 -18
- package/package.json +1 -1
package/lib/server.js
CHANGED
|
@@ -171,13 +171,22 @@ tool(
|
|
|
171
171
|
}
|
|
172
172
|
);
|
|
173
173
|
|
|
174
|
+
tool(
|
|
175
|
+
"guidelines_to_write_code",
|
|
176
|
+
"Read production-grade coding guidelines from the bundled mcp-production-grade.json file and use them when writing code. This ensures code follows established patterns and standards.",
|
|
177
|
+
{},
|
|
178
|
+
async () => {
|
|
179
|
+
return "Read production-grade coding guidelines from the bundled mcp-production-grade.json file and use them when writing code. This ensures code follows established patterns and standards.";
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
|
|
174
183
|
tool("mobile_list_elements_on_screen", "List elements on screen in a simplified, flattened structure. Returns only useful attributes: text, class, id (resource-id), accessibilityId (content-desc), and bounds. Do not cache this result.", {}, async ({}) => {
|
|
175
184
|
requireRobot();
|
|
176
185
|
const elements = await robot.getSimplifiedElements();
|
|
177
186
|
return `Screen elements (${elements.length} found): ${JSON.stringify(elements, null, 2)}`;
|
|
178
187
|
});
|
|
179
188
|
|
|
180
|
-
|
|
189
|
+
tool("mobile_press_button", "Press a button on device", {
|
|
181
190
|
button: zod_1.z.string().describe("The button to press. Supported buttons: BACK (android only), HOME, VOLUME_UP, VOLUME_DOWN, ENTER, DPAD_CENTER (android tv only), DPAD_UP (android tv only), DPAD_DOWN (android tv only), DPAD_LEFT (android tv only), DPAD_RIGHT (android tv only)"),
|
|
182
191
|
}, async ({ button }) => {
|
|
183
192
|
requireRobot();
|
|
@@ -185,7 +194,7 @@ tool(
|
|
|
185
194
|
return `Pressed the button: ${button}`;
|
|
186
195
|
});
|
|
187
196
|
|
|
188
|
-
tool("
|
|
197
|
+
tool("mobile_open_deeplink", "Open a deeplink in app on device", {
|
|
189
198
|
url: zod_1.z.string().describe("The URL to open"),
|
|
190
199
|
}, async ({ url }) => {
|
|
191
200
|
requireRobot();
|
|
@@ -230,33 +239,49 @@ tool(
|
|
|
230
239
|
|
|
231
240
|
tool(
|
|
232
241
|
"mobile_tap_by_text",
|
|
233
|
-
"Tap an element on screen by
|
|
242
|
+
"Tap an element on screen by any attribute: text, accessibilityId (content-desc), or id (resource-id). Searches all attributes automatically.",
|
|
234
243
|
{
|
|
235
|
-
|
|
244
|
+
value: zod_1.z.string().describe("The value to search for - can be text, accessibilityId, or id"),
|
|
236
245
|
},
|
|
237
|
-
async ({
|
|
238
|
-
if (!
|
|
246
|
+
async ({ value }) => {
|
|
247
|
+
if (!value) throw new Error("Input value is required");
|
|
239
248
|
|
|
240
249
|
requireRobot(); // ensure robot instance available
|
|
241
|
-
const elements = await robot.
|
|
250
|
+
const elements = await robot.getSimplifiedElements();
|
|
242
251
|
|
|
243
|
-
// Find element by
|
|
252
|
+
// Find element by matching any attribute (text, accessibilityId, or id)
|
|
244
253
|
const element = elements.find(
|
|
245
|
-
el => el.text ===
|
|
254
|
+
el => el.text === value || el.accessibilityId === value || el.id === value
|
|
246
255
|
);
|
|
247
256
|
|
|
248
|
-
if (!element) throw new Error(`Element with
|
|
249
|
-
|
|
257
|
+
if (!element) throw new Error(`Element with value "${value}" not found in text, accessibilityId, or id`);
|
|
258
|
+
|
|
259
|
+
// Parse bounds to get coordinates
|
|
260
|
+
// Bounds format: "[x1,y1][x2,y2]"
|
|
261
|
+
if (!element.bounds) throw new Error("Element has no bounds information");
|
|
262
|
+
|
|
263
|
+
const boundsMatch = element.bounds.match(/\[(\d+),(\d+)\]\[(\d+),(\d+)\]/);
|
|
264
|
+
if (!boundsMatch) throw new Error("Invalid bounds format");
|
|
265
|
+
|
|
266
|
+
const x1 = parseInt(boundsMatch[1]);
|
|
267
|
+
const y1 = parseInt(boundsMatch[2]);
|
|
268
|
+
const x2 = parseInt(boundsMatch[3]);
|
|
269
|
+
const y2 = parseInt(boundsMatch[4]);
|
|
270
|
+
|
|
250
271
|
// Calculate center coordinates
|
|
251
|
-
const
|
|
252
|
-
const
|
|
253
|
-
|
|
272
|
+
const x = Math.floor((x1 + x2) / 2);
|
|
273
|
+
const y = Math.floor((y1 + y2) / 2);
|
|
274
|
+
|
|
275
|
+
// Execute tap using robot (works for both Android and iOS)
|
|
276
|
+
await robot.tap(x, y);
|
|
254
277
|
|
|
255
|
-
//
|
|
256
|
-
|
|
257
|
-
|
|
278
|
+
// Determine which attribute matched
|
|
279
|
+
let matchedBy = '';
|
|
280
|
+
if (element.text === value) matchedBy = 'text';
|
|
281
|
+
else if (element.accessibilityId === value) matchedBy = 'accessibilityId';
|
|
282
|
+
else if (element.id === value) matchedBy = 'id';
|
|
258
283
|
|
|
259
|
-
return `Tapped element
|
|
284
|
+
return `Tapped element by ${matchedBy} "${value}" at (${x},${y})`;
|
|
260
285
|
}
|
|
261
286
|
);
|
|
262
287
|
|