appium-mcp 1.7.5 → 1.8.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.
Files changed (201) hide show
  1. package/.github/workflows/ci.yml +3 -0
  2. package/CHANGELOG.md +22 -0
  3. package/dist/devicemanager/adb-manager.d.ts +1 -0
  4. package/dist/devicemanager/adb-manager.d.ts.map +1 -0
  5. package/dist/devicemanager/adb-manager.js +5 -5
  6. package/dist/devicemanager/adb-manager.js.map +1 -1
  7. package/dist/devicemanager/ios-manager.d.ts +1 -0
  8. package/dist/devicemanager/ios-manager.d.ts.map +1 -0
  9. package/dist/devicemanager/ios-manager.js +2 -0
  10. package/dist/devicemanager/ios-manager.js.map +1 -1
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/locators/element-filter.d.ts +1 -0
  14. package/dist/locators/element-filter.d.ts.map +1 -0
  15. package/dist/locators/generate-all-locators.d.ts +1 -0
  16. package/dist/locators/generate-all-locators.d.ts.map +1 -0
  17. package/dist/locators/locator-generation.d.ts +1 -0
  18. package/dist/locators/locator-generation.d.ts.map +1 -0
  19. package/dist/locators/source-parsing.d.ts +1 -0
  20. package/dist/locators/source-parsing.d.ts.map +1 -0
  21. package/dist/logger.d.ts +2 -1
  22. package/dist/logger.d.ts.map +1 -0
  23. package/dist/resources/index.d.ts +1 -0
  24. package/dist/resources/index.d.ts.map +1 -0
  25. package/dist/resources/java/template.d.ts +1 -0
  26. package/dist/resources/java/template.d.ts.map +1 -0
  27. package/dist/schema.d.ts +1 -0
  28. package/dist/schema.d.ts.map +1 -0
  29. package/dist/scripts/simple-index-documentation.d.ts +1 -0
  30. package/dist/scripts/simple-index-documentation.d.ts.map +1 -0
  31. package/dist/scripts/simple-query-documentation.d.ts +1 -0
  32. package/dist/scripts/simple-query-documentation.d.ts.map +1 -0
  33. package/dist/server.d.ts +1 -0
  34. package/dist/server.d.ts.map +1 -0
  35. package/dist/session-store.d.ts +16 -2
  36. package/dist/session-store.d.ts.map +1 -0
  37. package/dist/session-store.js +21 -0
  38. package/dist/session-store.js.map +1 -1
  39. package/dist/tests/__mocks__/@appium/support.d.ts +1 -0
  40. package/dist/tests/__mocks__/@appium/support.d.ts.map +1 -0
  41. package/dist/tests/generate-all-locators.test.d.ts +1 -0
  42. package/dist/tests/generate-all-locators.test.d.ts.map +1 -0
  43. package/dist/tests/screenshot.test.d.ts +1 -0
  44. package/dist/tests/screenshot.test.d.ts.map +1 -0
  45. package/dist/tests/screenshot.test.js +6 -5
  46. package/dist/tests/screenshot.test.js.map +1 -1
  47. package/dist/tests/test-setup-wda.d.ts +1 -0
  48. package/dist/tests/test-setup-wda.d.ts.map +1 -0
  49. package/dist/tests/test-setup-wda.js +1 -3
  50. package/dist/tests/test-setup-wda.js.map +1 -1
  51. package/dist/tools/app-management/activate-app.d.ts +2 -1
  52. package/dist/tools/app-management/activate-app.d.ts.map +1 -0
  53. package/dist/tools/app-management/activate-app.js.map +1 -1
  54. package/dist/tools/app-management/install-app.d.ts +2 -1
  55. package/dist/tools/app-management/install-app.d.ts.map +1 -0
  56. package/dist/tools/app-management/install-app.js +6 -2
  57. package/dist/tools/app-management/install-app.js.map +1 -1
  58. package/dist/tools/app-management/list-apps.d.ts +2 -1
  59. package/dist/tools/app-management/list-apps.d.ts.map +1 -0
  60. package/dist/tools/app-management/list-apps.js +4 -1
  61. package/dist/tools/app-management/list-apps.js.map +1 -1
  62. package/dist/tools/app-management/terminate-app.d.ts +2 -1
  63. package/dist/tools/app-management/terminate-app.d.ts.map +1 -0
  64. package/dist/tools/app-management/terminate-app.js +6 -2
  65. package/dist/tools/app-management/terminate-app.js.map +1 -1
  66. package/dist/tools/app-management/uninstall-app.d.ts +2 -1
  67. package/dist/tools/app-management/uninstall-app.d.ts.map +1 -0
  68. package/dist/tools/app-management/uninstall-app.js +6 -2
  69. package/dist/tools/app-management/uninstall-app.js.map +1 -1
  70. package/dist/tools/context/get-contexts.d.ts +2 -1
  71. package/dist/tools/context/get-contexts.d.ts.map +1 -0
  72. package/dist/tools/context/get-contexts.js +4 -1
  73. package/dist/tools/context/get-contexts.js.map +1 -1
  74. package/dist/tools/context/switch-context.d.ts +2 -1
  75. package/dist/tools/context/switch-context.d.ts.map +1 -0
  76. package/dist/tools/context/switch-context.js +4 -1
  77. package/dist/tools/context/switch-context.js.map +1 -1
  78. package/dist/tools/documentation/answer-appium.d.ts +1 -0
  79. package/dist/tools/documentation/answer-appium.d.ts.map +1 -0
  80. package/dist/tools/documentation/index.d.ts +1 -0
  81. package/dist/tools/documentation/index.d.ts.map +1 -0
  82. package/dist/tools/documentation/reasoning-rag.d.ts +1 -0
  83. package/dist/tools/documentation/reasoning-rag.d.ts.map +1 -0
  84. package/dist/tools/documentation/reasoning-rag.js +3 -3
  85. package/dist/tools/documentation/reasoning-rag.js.map +1 -1
  86. package/dist/tools/documentation/sentence-transformers-embeddings.d.ts +1 -0
  87. package/dist/tools/documentation/sentence-transformers-embeddings.d.ts.map +1 -0
  88. package/dist/tools/documentation/sentence-transformers-embeddings.js +4 -3
  89. package/dist/tools/documentation/sentence-transformers-embeddings.js.map +1 -1
  90. package/dist/tools/documentation/simple-pdf-indexer.d.ts +1 -0
  91. package/dist/tools/documentation/simple-pdf-indexer.d.ts.map +1 -0
  92. package/dist/tools/index.d.ts +2 -1
  93. package/dist/tools/index.d.ts.map +1 -0
  94. package/dist/tools/interactions/click.d.ts +2 -1
  95. package/dist/tools/interactions/click.d.ts.map +1 -0
  96. package/dist/tools/interactions/click.js +4 -2
  97. package/dist/tools/interactions/click.js.map +1 -1
  98. package/dist/tools/interactions/double-tap.d.ts +2 -1
  99. package/dist/tools/interactions/double-tap.d.ts.map +1 -0
  100. package/dist/tools/interactions/double-tap.js +8 -4
  101. package/dist/tools/interactions/double-tap.js.map +1 -1
  102. package/dist/tools/interactions/drag-and-drop.d.ts +2 -1
  103. package/dist/tools/interactions/drag-and-drop.d.ts.map +1 -0
  104. package/dist/tools/interactions/drag-and-drop.js +4 -4
  105. package/dist/tools/interactions/drag-and-drop.js.map +1 -1
  106. package/dist/tools/interactions/find.d.ts +2 -1
  107. package/dist/tools/interactions/find.d.ts.map +1 -0
  108. package/dist/tools/interactions/find.js.map +1 -1
  109. package/dist/tools/interactions/get-page-source.d.ts +2 -1
  110. package/dist/tools/interactions/get-page-source.d.ts.map +1 -0
  111. package/dist/tools/interactions/get-page-source.js.map +1 -1
  112. package/dist/tools/interactions/get-text.d.ts +2 -1
  113. package/dist/tools/interactions/get-text.d.ts.map +1 -0
  114. package/dist/tools/interactions/get-text.js +4 -2
  115. package/dist/tools/interactions/get-text.js.map +1 -1
  116. package/dist/tools/interactions/long-press.d.ts +2 -1
  117. package/dist/tools/interactions/long-press.d.ts.map +1 -0
  118. package/dist/tools/interactions/long-press.js +12 -5
  119. package/dist/tools/interactions/long-press.js.map +1 -1
  120. package/dist/tools/interactions/screenshot.d.ts +6 -4
  121. package/dist/tools/interactions/screenshot.d.ts.map +1 -0
  122. package/dist/tools/interactions/screenshot.js +6 -3
  123. package/dist/tools/interactions/screenshot.js.map +1 -1
  124. package/dist/tools/interactions/set-value.d.ts +2 -1
  125. package/dist/tools/interactions/set-value.d.ts.map +1 -0
  126. package/dist/tools/interactions/set-value.js +4 -2
  127. package/dist/tools/interactions/set-value.js.map +1 -1
  128. package/dist/tools/ios/boot-simulator.d.ts +1 -0
  129. package/dist/tools/ios/boot-simulator.d.ts.map +1 -0
  130. package/dist/tools/ios/install-wda.d.ts +1 -0
  131. package/dist/tools/ios/install-wda.d.ts.map +1 -0
  132. package/dist/tools/ios/setup-wda.d.ts +1 -0
  133. package/dist/tools/ios/setup-wda.d.ts.map +1 -0
  134. package/dist/tools/navigations/scroll-to-element.d.ts +1 -0
  135. package/dist/tools/navigations/scroll-to-element.d.ts.map +1 -0
  136. package/dist/tools/navigations/scroll-to-element.js +2 -2
  137. package/dist/tools/navigations/scroll-to-element.js.map +1 -1
  138. package/dist/tools/navigations/scroll.d.ts +1 -0
  139. package/dist/tools/navigations/scroll.d.ts.map +1 -0
  140. package/dist/tools/navigations/scroll.js +19 -9
  141. package/dist/tools/navigations/scroll.js.map +1 -1
  142. package/dist/tools/navigations/swipe.d.ts +1 -0
  143. package/dist/tools/navigations/swipe.d.ts.map +1 -0
  144. package/dist/tools/navigations/swipe.js +11 -5
  145. package/dist/tools/navigations/swipe.js.map +1 -1
  146. package/dist/tools/session/create-session.d.ts +31 -0
  147. package/dist/tools/session/create-session.d.ts.map +1 -0
  148. package/dist/tools/session/create-session.js +88 -21
  149. package/dist/tools/session/create-session.js.map +1 -1
  150. package/dist/tools/session/delete-session.d.ts +1 -0
  151. package/dist/tools/session/delete-session.d.ts.map +1 -0
  152. package/dist/tools/session/delete-session.js +10 -1
  153. package/dist/tools/session/delete-session.js.map +1 -1
  154. package/dist/tools/session/select-device.d.ts +1 -0
  155. package/dist/tools/session/select-device.d.ts.map +1 -0
  156. package/dist/tools/session/select-device.js +11 -4
  157. package/dist/tools/session/select-device.js.map +1 -1
  158. package/dist/tools/session/select-platform.d.ts +1 -0
  159. package/dist/tools/session/select-platform.d.ts.map +1 -0
  160. package/dist/tools/session/select-platform.js +12 -5
  161. package/dist/tools/session/select-platform.js.map +1 -1
  162. package/dist/tools/test-generation/generate-tests.d.ts +2 -1
  163. package/dist/tools/test-generation/generate-tests.d.ts.map +1 -0
  164. package/dist/tools/test-generation/locators.d.ts +1 -0
  165. package/dist/tools/test-generation/locators.d.ts.map +1 -0
  166. package/dist/tools/test-generation/locators.js +4 -2
  167. package/dist/tools/test-generation/locators.js.map +1 -1
  168. package/dist/ui/mcp-ui-utils.d.ts +1 -0
  169. package/dist/ui/mcp-ui-utils.d.ts.map +1 -0
  170. package/package.json +6 -6
  171. package/server.json +2 -2
  172. package/src/session-store.ts +34 -2
  173. package/src/tests/screenshot.test.ts +6 -5
  174. package/src/tools/app-management/activate-app.ts +2 -2
  175. package/src/tools/app-management/install-app.ts +12 -3
  176. package/src/tools/app-management/list-apps.ts +12 -3
  177. package/src/tools/app-management/terminate-app.ts +12 -3
  178. package/src/tools/app-management/uninstall-app.ts +12 -3
  179. package/src/tools/context/get-contexts.ts +10 -4
  180. package/src/tools/context/switch-context.ts +17 -6
  181. package/src/tools/index.ts +1 -1
  182. package/src/tools/interactions/click.ts +6 -3
  183. package/src/tools/interactions/double-tap.ts +19 -7
  184. package/src/tools/interactions/drag-and-drop.ts +16 -7
  185. package/src/tools/interactions/find.ts +5 -2
  186. package/src/tools/interactions/get-page-source.ts +2 -2
  187. package/src/tools/interactions/get-text.ts +6 -3
  188. package/src/tools/interactions/long-press.ts +22 -10
  189. package/src/tools/interactions/screenshot.ts +11 -5
  190. package/src/tools/interactions/set-value.ts +9 -3
  191. package/src/tools/navigations/scroll-to-element.ts +4 -4
  192. package/src/tools/navigations/scroll.ts +25 -10
  193. package/src/tools/navigations/swipe.ts +17 -6
  194. package/src/tools/session/create-session.ts +108 -27
  195. package/src/tools/session/delete-session.ts +10 -1
  196. package/src/tools/session/select-device.ts +11 -4
  197. package/src/tools/session/select-platform.ts +12 -5
  198. package/src/tools/test-generation/generate-tests.ts +1 -1
  199. package/src/tools/test-generation/locators.ts +8 -3
  200. package/tsconfig.json +7 -15
  201. package/tsconfig.tsbuildinfo +1 -0
@@ -2,8 +2,9 @@
2
2
  * Tool to create a new mobile session (Android or iOS)
3
3
  */
4
4
  import { z } from 'zod';
5
- import { access, readFile } from 'fs/promises';
6
- import { constants } from 'fs';
5
+ import { access, readFile } from 'node:fs/promises';
6
+ import { constants } from 'node:fs';
7
+ import { URL } from 'node:url';
7
8
  import { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver';
8
9
  import { XCUITestDriver } from 'appium-xcuitest-driver';
9
10
  import {
@@ -24,6 +25,7 @@ import {
24
25
  createSessionDashboardUI,
25
26
  addUIResourceToResponse,
26
27
  } from '../../ui/mcp-ui-utils.js';
28
+ import WebDriver from 'webdriver';
27
29
 
28
30
  // Define capabilities type
29
31
  interface Capabilities {
@@ -76,7 +78,8 @@ function filterEmptyCapabilities(capabilities: Capabilities): Capabilities {
76
78
  */
77
79
  function buildAndroidCapabilities(
78
80
  configCaps: Record<string, any>,
79
- customCaps: Record<string, any> | undefined
81
+ customCaps: Record<string, any> | undefined,
82
+ isRemoteServer: boolean
80
83
  ): Capabilities {
81
84
  const defaultCaps: Capabilities = {
82
85
  platformName: 'Android',
@@ -84,7 +87,7 @@ function buildAndroidCapabilities(
84
87
  'appium:deviceName': 'Android Device',
85
88
  };
86
89
 
87
- const selectedDeviceUdid = getSelectedDevice();
90
+ const selectedDeviceUdid = isRemoteServer ? undefined : getSelectedDevice();
88
91
 
89
92
  const capabilities = {
90
93
  ...defaultCaps,
@@ -128,9 +131,10 @@ async function validateIOSDeviceSelection(
128
131
  */
129
132
  async function buildIOSCapabilities(
130
133
  configCaps: Record<string, any>,
131
- customCaps: Record<string, any> | undefined
134
+ customCaps: Record<string, any> | undefined,
135
+ isRemoteServer: boolean
132
136
  ): Promise<Capabilities> {
133
- const deviceType = getSelectedDeviceType();
137
+ const deviceType = isRemoteServer ? null : getSelectedDeviceType();
134
138
  await validateIOSDeviceSelection(deviceType);
135
139
 
136
140
  const defaultCaps: Capabilities = {
@@ -139,8 +143,10 @@ async function buildIOSCapabilities(
139
143
  'appium:deviceName': 'iPhone Simulator',
140
144
  };
141
145
 
142
- const selectedDeviceUdid = getSelectedDevice();
143
- const selectedDeviceInfo = getSelectedDeviceInfo();
146
+ const selectedDeviceUdid = isRemoteServer ? undefined : getSelectedDevice();
147
+ const selectedDeviceInfo = isRemoteServer
148
+ ? undefined
149
+ : getSelectedDeviceInfo();
144
150
 
145
151
  log.debug('Selected device info:', selectedDeviceInfo);
146
152
 
@@ -202,22 +208,69 @@ async function createDriverSession(
202
208
  return sessionId;
203
209
  }
204
210
 
211
+ /**
212
+ * Registers a tool for creating a new mobile session with Android or iOS devices.
213
+ *
214
+ * This function adds a 'create_session' tool to the provided server that handles
215
+ * mobile session creation with support for both local and remote Appium servers.
216
+ *
217
+ * @param server - The server instance to which the create_session tool will be added
218
+ *
219
+ * @tool create_session
220
+ * @description Creates a new mobile session with Android or iOS device. Requires prior
221
+ * platform selection via the select_platform tool. Supports both local and remote
222
+ * Appium server connections.
223
+ *
224
+ * @param {Object} args - Tool execution arguments
225
+ * @param {'ios' | 'android'} args.platform - REQUIRED. The target platform, must match
226
+ * the platform explicitly selected via select_platform tool
227
+ * @param {Object} [args.capabilities] - Optional custom W3C format capabilities
228
+ * @param {string} [args.remoteServerUrl] - Optional remote Appium server URL
229
+ * (e.g., http://localhost:4723). If not provided, uses local Appium server
230
+ *
231
+ * @returns {Promise<Object>} Response object containing:
232
+ * - text: Success message with session ID and device details
233
+ * - ui: Interactive session dashboard UI component
234
+ *
235
+ * @throws {Error} If session creation fails or platform capabilities cannot be loaded
236
+ *
237
+ * @example
238
+ * // Register the tool
239
+ * createSession(server);
240
+ */
205
241
  export default function createSession(server: any): void {
206
242
  server.addTool({
207
243
  name: 'create_session',
208
244
  description: `Create a new mobile session with Android or iOS device.
209
- MUST use select_platform tool first to ask the user which platform they want.
210
- DO NOT assume or default to any platform.
245
+ WORKFLOW FOR LOCAL SERVERS (no remoteServerUrl):
246
+ - Use select_platform tool FIRST to ask the user which platform they want
247
+ - Then optionally use select_device tool if multiple devices are available
248
+ - Finally call create_session with the selected platform and device
249
+ - DO NOT assume or default to any platform
250
+ WORKFLOW FOR REMOTE SERVERS (remoteServerUrl provided):
251
+ - SKIP select_platform tool entirely
252
+ - Infer the platform from the user's request (e.g., 'ios', 'android')
253
+ - Infer device type from context when possible (e.g., 'simulator', 'real device')
254
+ - Call create_session directly with platform, remoteServerUrl, and any other capabilities from the user's request
255
+ - Example: User says 'start session with http://localhost:4723 for ios with iphone 17' → infer platform='ios' and call create_session with remoteServerUrl and platform parameters
211
256
  `,
212
257
  parameters: z.object({
213
258
  platform: z.enum(['ios', 'android']).describe(
214
- `REQUIRED: Must match the platform the user explicitly selected via the select_platform tool.
215
- DO NOT default to Android or iOS without asking the user first.`
259
+ `REQUIRED: Platform to use. For local servers, this must match the platform the user explicitly selected via the select_platform tool.
260
+ If remoteServerUrl is provided, the assistant should ask the user to confirm or infer the platform from the conversation; do not assume a default.`
216
261
  ),
217
262
  capabilities: z
218
263
  .object({})
219
264
  .optional()
220
- .describe('Optional custom capabilities for the session (W3C format).'),
265
+ .describe(
266
+ 'Optional custom W3C format capabilities for the session. Common options include appium:app (app path), appium:deviceName, appium:platformVersion, appium:bundleId, appium:autoGrantPermissions, etc. Custom capabilities override default and config file settings.'
267
+ ),
268
+ remoteServerUrl: z
269
+ .string()
270
+ .optional()
271
+ .describe(
272
+ 'Remote Appium server URL (e.g., http://localhost:4723 or http://192.168.1.100:4723). If not provided, uses local Appium server.'
273
+ ),
221
274
  }),
222
275
  annotations: {
223
276
  readOnlyHint: false,
@@ -229,31 +282,59 @@ export default function createSession(server: any): void {
229
282
  log.info(
230
283
  'Existing session detected, cleaning up before creating new session...'
231
284
  );
232
- await safeDeleteSession();
285
+ try {
286
+ await safeDeleteSession();
287
+ } catch {
288
+ // ok to ignore
289
+ }
233
290
  }
234
291
 
235
- const { platform, capabilities: customCapabilities } = args;
292
+ const {
293
+ platform,
294
+ capabilities: customCapabilities,
295
+ remoteServerUrl,
296
+ } = args;
236
297
 
237
298
  const configCapabilities = await loadCapabilitiesConfig();
238
299
  const platformCaps =
239
300
  platform === 'android'
240
301
  ? configCapabilities.android
241
302
  : configCapabilities.ios;
242
-
243
303
  const finalCapabilities =
244
304
  platform === 'android'
245
- ? buildAndroidCapabilities(platformCaps, customCapabilities)
246
- : await buildIOSCapabilities(platformCaps, customCapabilities);
247
-
248
- const driver = createDriverForPlatform(platform);
249
-
250
- log.info(
251
- `Creating new ${platform.toUpperCase()} session with capabilities:`,
252
- JSON.stringify(finalCapabilities, null, 2)
253
- );
305
+ ? buildAndroidCapabilities(
306
+ platformCaps,
307
+ customCapabilities,
308
+ !!remoteServerUrl
309
+ )
310
+ : await buildIOSCapabilities(
311
+ platformCaps,
312
+ customCapabilities,
313
+ !!remoteServerUrl
314
+ );
315
+
316
+ let sessionId;
317
+ if (remoteServerUrl) {
318
+ const remoteUrl = new URL(remoteServerUrl);
319
+ const client = await WebDriver.newSession({
320
+ protocol: remoteUrl.protocol.replace(':', ''),
321
+ hostname: remoteUrl.hostname,
322
+ port: parseInt(remoteUrl.port, 10),
323
+ path: remoteUrl.pathname,
324
+ capabilities: finalCapabilities,
325
+ });
326
+ sessionId = client.sessionId;
327
+ setSession(client, client.sessionId);
328
+ } else {
329
+ log.info(
330
+ `Creating new ${platform.toUpperCase()} session with capabilities:`,
331
+ JSON.stringify(finalCapabilities, null, 2)
332
+ );
254
333
 
255
- const sessionId = await createDriverSession(driver, finalCapabilities);
256
- setSession(driver, sessionId);
334
+ const driver = createDriverForPlatform(platform);
335
+ sessionId = await createDriverSession(driver, finalCapabilities);
336
+ setSession(driver, sessionId);
337
+ }
257
338
 
258
339
  // Safely convert sessionId to string for display
259
340
  const sessionIdStr =
@@ -40,7 +40,16 @@ export default function deleteSession(server: any): void {
40
40
  }
41
41
  } catch (error: any) {
42
42
  log.error(`Error deleting session`, error);
43
- throw new Error(`Failed to delete session: ${error.message}`);
43
+ // don't need to raise an error since session end means anyway we should create a new session
44
+ // to proceed further requests.
45
+ return {
46
+ content: [
47
+ {
48
+ type: 'text',
49
+ text: `Session delete might fail as error ${error}`,
50
+ },
51
+ ],
52
+ };
44
53
  }
45
54
  },
46
55
  });
@@ -269,10 +269,17 @@ async function handleIOSDeviceSelection(
269
269
  export default function selectDevice(server: any): void {
270
270
  server.addTool({
271
271
  name: 'select_device',
272
- description: `REQUIRED when multiple devices are found: Ask the user to select which specific device they want to use from the available devices.
273
- This tool lists all available devices and allows selection by UDID.
274
- You MUST use this tool when select_platform returns multiple devices before calling create_session for android.
275
- You MUST use this tool when select_platform returns multiple devices before calling boot_simulator for ios if the user has selected simulator device type.
272
+ description: `Select a specific device from available LOCAL devices. For LOCAL Appium servers ONLY.
273
+ DO NOT use this tool for REMOTE Appium servers - remoteServerUrl indicates a remote server.
274
+ WORKFLOW FOR LOCAL SERVERS:
275
+ - Use this tool ONLY when select_platform returns multiple devices
276
+ - For Android: Use before calling create_session if multiple devices are found
277
+ - For iOS: Use before calling boot_simulator or create_session if multiple simulators/devices are found
278
+ - Ask the user which device they want to use from the list provided
279
+ WORKFLOW FOR REMOTE SERVERS:
280
+ - SKIP this tool entirely
281
+ - Device selection should be handled via capabilities in create_session (e.g., appium:deviceName, appium:udid)
282
+ - The remote Appium server is already configured for specific device(s)
276
283
  `,
277
284
  parameters: z.object({
278
285
  platform: z
@@ -195,10 +195,17 @@ async function handleIOSPlatformSelection(
195
195
  export default function selectPlatform(server: any): void {
196
196
  server.addTool({
197
197
  name: 'select_platform',
198
- description: `REQUIRED: First ASK THE USER which mobile platform they want to use (Android or iOS) before creating a session.
199
- DO NOT assume or default to any platform.
200
- You MUST explicitly prompt the user to choose between Android or iOS.
201
- This is mandatory before proceeding to use the create_session tool.
198
+ description: `Select the mobile platform for LOCAL Appium servers ONLY.
199
+ DO NOT use this tool if the user mentions a REMOTE Appium server URL (e.g., http://localhost:4723, http://192.168.1.100:4723, or any other server address).
200
+ WORKFLOW FOR LOCAL SERVERS:
201
+ 1. First, ASK THE USER which mobile platform they want to use (Android or iOS)
202
+ 2. You MUST explicitly prompt the user to choose between Android or iOS
203
+ 3. DO NOT assume or default to any platform
204
+ 4. After platform selection, available devices will be listed
205
+ 5. If multiple devices are available, use select_device to let the user choose
206
+ 6. After device selection, proceed to create_session
207
+ WORKFLOW FOR REMOTE SERVERS:
208
+ If user provides a remote server URL, SKIP this tool entirely. Instead, infer the platform and device type from the user's request (e.g., 'ios xcuitest driver with iphone 17 simulator' means platform='ios') and call create_session directly with the remoteServerUrl parameter.
202
209
  `,
203
210
  parameters: z.object({
204
211
  platform: z
@@ -210,7 +217,7 @@ export default function selectPlatform(server: any): void {
210
217
  .enum(['simulator', 'real'])
211
218
  .optional()
212
219
  .describe(
213
- "For iOS only: Specify whether to use 'simulator' or 'real' device. REQUIRED when platform is 'ios'."
220
+ "For iOS only: Specify whether to use 'simulator' (iOS Simulator on macOS) or 'real' (physical iOS device). REQUIRED when platform is 'ios'."
214
221
  ),
215
222
  }),
216
223
  annotations: {
@@ -1,4 +1,4 @@
1
- import { FastMCP } from 'fastmcp/dist/FastMCP.js';
1
+ import { FastMCP } from 'fastmcp';
2
2
  import { z } from 'zod';
3
3
 
4
4
  export default function generateTest(server: FastMCP): void {
@@ -10,7 +10,7 @@
10
10
  * For detailed documentation on adding tools, see docs/CONTRIBUTING.md
11
11
  */
12
12
  import { z } from 'zod';
13
- import { getDriver } from '../../session-store.js';
13
+ import { getDriver, isRemoteDriverSession } from '../../session-store.js';
14
14
  import { generateAllElementLocators } from '../../locators/generate-all-locators.js';
15
15
  import log from '../../logger.js';
16
16
  import {
@@ -18,6 +18,7 @@ import {
18
18
  createLocatorGeneratorUI,
19
19
  addUIResourceToResponse,
20
20
  } from '../../ui/mcp-ui-utils.js';
21
+ import type { Client } from 'webdriver';
21
22
 
22
23
  export default function generateLocators(server: any): void {
23
24
  server.addTool({
@@ -42,8 +43,12 @@ export default function generateLocators(server: any): void {
42
43
 
43
44
  try {
44
45
  // Get the page source from the driver
45
- const pageSource = await driver.getPageSource();
46
- const driverName = (await driver.caps.automationName).toLowerCase();
46
+ const pageSource = await (driver as any).getPageSource();
47
+ const driverName = isRemoteDriverSession(driver)
48
+ ? (driver as Client).capabilities[
49
+ 'appium:automationName'
50
+ ]?.toLowerCase()
51
+ : (await (driver as any).caps.automationName).toLowerCase();
47
52
  if (!pageSource) {
48
53
  throw new Error('Page source is empty or null');
49
54
  }
package/tsconfig.json CHANGED
@@ -1,23 +1,15 @@
1
1
  {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@appium/tsconfig/tsconfig.json",
2
4
  "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "esModuleInterop": true,
7
- "resolveJsonModule": true,
8
- "strict": true,
9
- "skipLibCheck": true,
10
5
  "outDir": "dist",
11
6
  "sourceMap": true,
12
7
  "declaration": true,
13
- "allowSyntheticDefaultImports": true,
14
- "forceConsistentCasingInFileNames": true,
15
- "isolatedModules": true,
16
- "baseUrl": ".",
17
- "paths": {
18
- "*": ["node_modules/*"]
19
- }
8
+ "resolveJsonModule": true,
9
+ "rootDir": "src",
10
+ "module": "NodeNext",
11
+ "moduleResolution": "NodeNext"
20
12
  },
21
13
  "include": ["src/**/*"],
22
14
  "exclude": ["node_modules", "dist"]
23
- }
15
+ }