@nbakka/mcp-appium 2.0.21 → 2.0.23
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/app_context.txt +21 -0
- package/lib/secret.json +13 -0
- package/lib/server.js +17 -29
- package/package.json +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
When asked to open buy SRP, use deeplink to open https://housing.com/in/buy/mumbai/<locality name>. For example: if asked to open 'Mira Road East' buy SRP, then open this deeplink: https://housing.com/in/buy/mumbai/mira_road_east
|
|
2
|
+
Homepage deeplink -> https://housing.com/in/buy/real-estate-mumbai
|
|
3
|
+
Project dedicated page deeplink -> https://housing.com/in/buy/projects/page/319874-sunteck-sky-park-by-sunteck-realty-limited-in-mira-road-east
|
|
4
|
+
Filters on the filter screen may initially be offscreen and require scrolling to view.
|
|
5
|
+
Stop execution if any step fails.
|
|
6
|
+
(Remember this properly - Very important) After the execution is successful/completed, do NOT analyze what you found or did; only generate Appium code.
|
|
7
|
+
Print the Java/Appium code. In our framework, we use the following methods:
|
|
8
|
+
- waitForElementToBeVisible("locator_key", Wait.SHORT); locator_key is locator key and wait can be SHORT, MEDIUM, or LONG.
|
|
9
|
+
- scrollDown(n); // n is the number of times to scroll.
|
|
10
|
+
- navigateBack(); // for back action.
|
|
11
|
+
- deepLink.OpenDeepLink("deeplink_key"); // deeplink_key is deeplink name.
|
|
12
|
+
- getText("locator_key"); // to get text of element.
|
|
13
|
+
Using the above, return code that looks like:
|
|
14
|
+
deepLink.OpenDeepLink(deeplink); // deeplink -> https://housing.com
|
|
15
|
+
waitForElementToBeVisible("view_on_map", Wait.LONG); // view_on_map=//android.widget.TextView[@text="View On Map"]; here xpath should be comments so it can be pasted in xpath sheet.
|
|
16
|
+
When giving output, please remove escape characters before double quotes.
|
|
17
|
+
Do similarly for click and sendKeys methods:
|
|
18
|
+
- click("search_select")
|
|
19
|
+
- sendKeys("locator_key", "string_to_be_passed", Wait.LONG)
|
|
20
|
+
Figure out dynamic paths like //android.widget.TextView[@text="View 180 Properties"] here 180 is not constant so create a xpath like //android.widget.TextView[contains(@text,"View") and contains(@text,"Properties")]
|
|
21
|
+
For repeating logic, create loops
|
package/lib/secret.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "service_account",
|
|
3
|
+
"project_id": "gen-lang-client-0998595520",
|
|
4
|
+
"private_key_id": "99b60e861b2815a0b7e4946fa0697d70f157b4a6",
|
|
5
|
+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCylqcylIgnlYFv\nSDSNA5w54FBTGKqwhg55bUYZoO3PYvXywgUDUO/q7jSLIYOLzQb+yiSKOBbJKTrs\ng/HP8Qr/vGoLJBXmEmhheh2YEip2uDERTeIaC9ilyWoDgRa8bWnj2DKUVlEAKK29\nK2cl7k3sejS9QNXW7b38ov3qb4uQK4tBy28rlUs2SpElNsMbO+RJOWxSuRqlWXER\nFD2alSmWB8ZB6ugHeOXsx5kKkNzDlS2wDKQJqZNWqga8LpSl+9lENrdi59qKuRgq\n053N5M/WLGJWyg8W2BWXMhZGCak1NcgPanQ/vFLO2mIljowb8mxtNML6rZfLawKp\nbFre03cZAgMBAAECggEAAJTwD4CfXu2kQc4M6cawvBmIeXTTnYaaRnf+Kfg1vh62\n6WcLaCLb3TqQbkGaMZrl4m+bJd4f6ODbAck+QOyqmgGtoMKp1ZmKwIKK1SN+Auv/\nsOw9h9MxDf01fLRvdAaxOR5Lr+MGGYeIZVzeVafMljAhutoauDwHCesoA5sAa+RP\nBzIa7+N6EmGt/FvAdKAvSuuZZsMUHLoOiHeB3knwjqoKJCHVMNWqpeMyqclIjR+O\nIv37jhlj2z7pbR0n6hfjYQLmGRfSRGvmw1hrDV1ije4RXeNs5/13gUokNf4kBhqn\nQ+t4eI6UEa82lgLS7Msmbcyyh2h2TfFG1Ygx6nYZHwKBgQDhUzdMjCtADBvQnSQw\nV+qWPzOJFdYzURgg1zMXUGnPws8vuUMjuCNEu3AUrtjvc5RVdePAIyN6o/j5HLAV\nt6qksoQkUas/daCzuRG9IWFw2eI0rhs+paMJVIUJQWXt60afgv61rsvLfIC/MBi9\ntl62xI8FNDWzPgSVWTXukIhOzwKBgQDK5p/3dr/S+oSk6E/y1bwejNm8b0VgqvwO\nP9OO2kmDEXTGSlXX5Mn1qW7Wg1n+z5NrDkA3IyRtEbILyylUELooGXVKiKPkiJpE\n+Qi+wsVqmThvqO6cYl8FW64/0UH88ZcvDjyDLfUsei4lY0hRjafTshaoqk0SOyq9\n4UOs3ioVlwKBgHYYtHoVWTHHZuivA+Gmopg+5dbqsArTbQ8BW5DTn7G5y/eaZRsa\njrmed/8PKTpPXKZyFH2GrTjBKmP+ajfnvLN3sRSMDXJER4cK78Yt8bFBMXMk8bii\n/dGND/Eq6q6JSsmd0bwNslijl6MdJUqBhCDM4pz6oU6hqatRR5gS/q43AoGBAIsp\nNGwQyS4V3mYQY80kpNq7NhdUpdvQSgIn6pzewG6hyVq63zes1oukQr3j5xSqH+zc\nIFTwyGn6KgiGtfjPZC5ej6CoKOh0fIJz33ies7ISFrAWyFj/6zYMlG12w3CN7mg6\ntmwuWCrCPeYsuwwcQRAj5ACYlTW82OrUlor48RpPAoGALtMf3SEALRuKvpSqDxpe\nw/XkD098Lq4g+uFbFfN0aL1gyuWvwQ4KtIkmMpENWYC/zFVH79AAWSA7gvEEWE0C\n3FP2lI29GgXPhG+EDS3/dvjY4UPcqDVMFYAen4Z4X0FnKa8Yr5rGPuYtZCsglGmh\nigkENMmOUL6T62YvJATeFd8=\n-----END PRIVATE KEY-----\n",
|
|
6
|
+
"client_email": "mcp-sheet-access@gen-lang-client-0998595520.iam.gserviceaccount.com",
|
|
7
|
+
"client_id": "104386077369721430122",
|
|
8
|
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
|
9
|
+
"token_uri": "https://oauth2.googleapis.com/token",
|
|
10
|
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
|
11
|
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/mcp-sheet-access%40gen-lang-client-0998595520.iam.gserviceaccount.com",
|
|
12
|
+
"universe_domain": "googleapis.com"
|
|
13
|
+
}
|
package/lib/server.js
CHANGED
|
@@ -17,9 +17,6 @@ const getAgentVersion = () => {
|
|
|
17
17
|
const json = require("../package.json");
|
|
18
18
|
return json.version;
|
|
19
19
|
};
|
|
20
|
-
const selectedSheetContext = {
|
|
21
|
-
sheetName: null,
|
|
22
|
-
};
|
|
23
20
|
|
|
24
21
|
const createMcpServer = () => {
|
|
25
22
|
const server = new mcp_js_1.McpServer({
|
|
@@ -149,7 +146,7 @@ const createMcpServer = () => {
|
|
|
149
146
|
async () => {
|
|
150
147
|
try {
|
|
151
148
|
// Read file from config folder
|
|
152
|
-
const filePath = path.join(__dirname, '
|
|
149
|
+
const filePath = path.join(__dirname, 'lib', 'app_context.txt');
|
|
153
150
|
const fileContent = await fs.readFile(filePath, 'utf-8');
|
|
154
151
|
|
|
155
152
|
// Assuming each note is separated by a newline
|
|
@@ -278,29 +275,18 @@ const createMcpServer = () => {
|
|
|
278
275
|
);
|
|
279
276
|
|
|
280
277
|
tool(
|
|
281
|
-
"
|
|
282
|
-
"MUST be
|
|
278
|
+
"fetch_google_sheet_locators",
|
|
279
|
+
"MUST be invoked before mobile_learn_current_app_context. Provide the Google Sheet name to fetch locatorName and androidLocator from the specified sheet.",
|
|
283
280
|
{
|
|
284
|
-
sheetName: {
|
|
281
|
+
sheetName: {
|
|
282
|
+
type: "string",
|
|
283
|
+
description: "Exact name of the Google Sheets tab (sheet) to fetch data from.",
|
|
284
|
+
required: true,
|
|
285
|
+
},
|
|
285
286
|
},
|
|
286
287
|
async ({ sheetName }) => {
|
|
287
|
-
if (!sheetName) {
|
|
288
|
-
return "Error: sheetName is required.";
|
|
289
|
-
}
|
|
290
|
-
selectedSheetContext.sheetName = sheetName.trim();
|
|
291
|
-
return `Sheet name "${selectedSheetContext.sheetName}" saved. Now call fetch_google_sheet_locators to fetch data.`;
|
|
292
|
-
}
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
// Tool 2: fetch locator data using previously selected sheet name
|
|
296
|
-
tool(
|
|
297
|
-
"fetch_google_sheet_locators",
|
|
298
|
-
"MUST be called after select_google_sheet. Fetch locatorName and androidLocator from the sheet set by select_google_sheet. Please call select_google_sheet first.",
|
|
299
|
-
{},
|
|
300
|
-
async () => {
|
|
301
|
-
const sheetName = selectedSheetContext.sheetName;
|
|
302
|
-
if (!sheetName) {
|
|
303
|
-
return "Error: Sheet name not set. Please call select_google_sheet first.";
|
|
288
|
+
if (!sheetName || sheetName.trim() === "") {
|
|
289
|
+
return "Error: sheetName is required and cannot be empty.";
|
|
304
290
|
}
|
|
305
291
|
|
|
306
292
|
try {
|
|
@@ -308,7 +294,7 @@ const createMcpServer = () => {
|
|
|
308
294
|
const path = require('path');
|
|
309
295
|
const { google } = require('googleapis');
|
|
310
296
|
|
|
311
|
-
//
|
|
297
|
+
// Adjust path to your config folder as needed
|
|
312
298
|
const keyFile = path.join(__dirname, 'config', 'secret.json');
|
|
313
299
|
const credentials = JSON.parse(await fs.readFile(keyFile, 'utf-8'));
|
|
314
300
|
|
|
@@ -329,12 +315,13 @@ const createMcpServer = () => {
|
|
|
329
315
|
return `Sheet "${sheetName}" is empty or does not exist.`;
|
|
330
316
|
}
|
|
331
317
|
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
const
|
|
318
|
+
// Normalize header keys for safe case-insensitive lookup
|
|
319
|
+
const header = rows[0].map(h => h.toString().toLowerCase().trim());
|
|
320
|
+
const locatorNameIdx = header.indexOf('locator name');
|
|
321
|
+
const androidLocatorIdx = header.findIndex(h => h === 'android xpath' || h === 'android locator');
|
|
335
322
|
|
|
336
323
|
if (locatorNameIdx === -1 || androidLocatorIdx === -1) {
|
|
337
|
-
return `Required columns "
|
|
324
|
+
return `Required columns "locator name" and/or "android xpath" not found in sheet "${sheetName}".`;
|
|
338
325
|
}
|
|
339
326
|
|
|
340
327
|
const extracted = rows.slice(1)
|
|
@@ -351,6 +338,7 @@ const createMcpServer = () => {
|
|
|
351
338
|
}
|
|
352
339
|
);
|
|
353
340
|
|
|
341
|
+
|
|
354
342
|
return server;
|
|
355
343
|
};
|
|
356
344
|
|