@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.
@@ -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
@@ -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, 'config', 'app_context.txt');
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
- "select_google_sheet",
282
- "MUST be called after mobile_learn_current_app_context to set the Google Sheet name to be used by fetch_google_sheet_locators.",
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: { type: "string", description: "Name of the sheet/tab to fetch from" }
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
- // Load credentials
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
- const header = rows[0].map(h => h.toString().toLowerCase());
333
- const locatorNameIdx = header.indexOf('locatorName');
334
- const androidLocatorIdx = header.findIndex(h => h === 'android xpath' || h === 'androidLocator');
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 "locatorName" and/or "androidXpath" not found in sheet "${sheetName}".`;
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbakka/mcp-appium",
3
- "version": "2.0.21",
3
+ "version": "2.0.23",
4
4
  "description": "Appium MCP",
5
5
  "engines": {
6
6
  "node": ">=18"