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.
- package/.github/workflows/ci.yml +3 -0
- package/CHANGELOG.md +22 -0
- package/dist/devicemanager/adb-manager.d.ts +1 -0
- package/dist/devicemanager/adb-manager.d.ts.map +1 -0
- package/dist/devicemanager/adb-manager.js +5 -5
- package/dist/devicemanager/adb-manager.js.map +1 -1
- package/dist/devicemanager/ios-manager.d.ts +1 -0
- package/dist/devicemanager/ios-manager.d.ts.map +1 -0
- package/dist/devicemanager/ios-manager.js +2 -0
- package/dist/devicemanager/ios-manager.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/locators/element-filter.d.ts +1 -0
- package/dist/locators/element-filter.d.ts.map +1 -0
- package/dist/locators/generate-all-locators.d.ts +1 -0
- package/dist/locators/generate-all-locators.d.ts.map +1 -0
- package/dist/locators/locator-generation.d.ts +1 -0
- package/dist/locators/locator-generation.d.ts.map +1 -0
- package/dist/locators/source-parsing.d.ts +1 -0
- package/dist/locators/source-parsing.d.ts.map +1 -0
- package/dist/logger.d.ts +2 -1
- package/dist/logger.d.ts.map +1 -0
- package/dist/resources/index.d.ts +1 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/java/template.d.ts +1 -0
- package/dist/resources/java/template.d.ts.map +1 -0
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/scripts/simple-index-documentation.d.ts +1 -0
- package/dist/scripts/simple-index-documentation.d.ts.map +1 -0
- package/dist/scripts/simple-query-documentation.d.ts +1 -0
- package/dist/scripts/simple-query-documentation.d.ts.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/session-store.d.ts +16 -2
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +21 -0
- package/dist/session-store.js.map +1 -1
- package/dist/tests/__mocks__/@appium/support.d.ts +1 -0
- package/dist/tests/__mocks__/@appium/support.d.ts.map +1 -0
- package/dist/tests/generate-all-locators.test.d.ts +1 -0
- package/dist/tests/generate-all-locators.test.d.ts.map +1 -0
- package/dist/tests/screenshot.test.d.ts +1 -0
- package/dist/tests/screenshot.test.d.ts.map +1 -0
- package/dist/tests/screenshot.test.js +6 -5
- package/dist/tests/screenshot.test.js.map +1 -1
- package/dist/tests/test-setup-wda.d.ts +1 -0
- package/dist/tests/test-setup-wda.d.ts.map +1 -0
- package/dist/tests/test-setup-wda.js +1 -3
- package/dist/tests/test-setup-wda.js.map +1 -1
- package/dist/tools/app-management/activate-app.d.ts +2 -1
- package/dist/tools/app-management/activate-app.d.ts.map +1 -0
- package/dist/tools/app-management/activate-app.js.map +1 -1
- package/dist/tools/app-management/install-app.d.ts +2 -1
- package/dist/tools/app-management/install-app.d.ts.map +1 -0
- package/dist/tools/app-management/install-app.js +6 -2
- package/dist/tools/app-management/install-app.js.map +1 -1
- package/dist/tools/app-management/list-apps.d.ts +2 -1
- package/dist/tools/app-management/list-apps.d.ts.map +1 -0
- package/dist/tools/app-management/list-apps.js +4 -1
- package/dist/tools/app-management/list-apps.js.map +1 -1
- package/dist/tools/app-management/terminate-app.d.ts +2 -1
- package/dist/tools/app-management/terminate-app.d.ts.map +1 -0
- package/dist/tools/app-management/terminate-app.js +6 -2
- package/dist/tools/app-management/terminate-app.js.map +1 -1
- package/dist/tools/app-management/uninstall-app.d.ts +2 -1
- package/dist/tools/app-management/uninstall-app.d.ts.map +1 -0
- package/dist/tools/app-management/uninstall-app.js +6 -2
- package/dist/tools/app-management/uninstall-app.js.map +1 -1
- package/dist/tools/context/get-contexts.d.ts +2 -1
- package/dist/tools/context/get-contexts.d.ts.map +1 -0
- package/dist/tools/context/get-contexts.js +4 -1
- package/dist/tools/context/get-contexts.js.map +1 -1
- package/dist/tools/context/switch-context.d.ts +2 -1
- package/dist/tools/context/switch-context.d.ts.map +1 -0
- package/dist/tools/context/switch-context.js +4 -1
- package/dist/tools/context/switch-context.js.map +1 -1
- package/dist/tools/documentation/answer-appium.d.ts +1 -0
- package/dist/tools/documentation/answer-appium.d.ts.map +1 -0
- package/dist/tools/documentation/index.d.ts +1 -0
- package/dist/tools/documentation/index.d.ts.map +1 -0
- package/dist/tools/documentation/reasoning-rag.d.ts +1 -0
- package/dist/tools/documentation/reasoning-rag.d.ts.map +1 -0
- package/dist/tools/documentation/reasoning-rag.js +3 -3
- package/dist/tools/documentation/reasoning-rag.js.map +1 -1
- package/dist/tools/documentation/sentence-transformers-embeddings.d.ts +1 -0
- package/dist/tools/documentation/sentence-transformers-embeddings.d.ts.map +1 -0
- package/dist/tools/documentation/sentence-transformers-embeddings.js +4 -3
- package/dist/tools/documentation/sentence-transformers-embeddings.js.map +1 -1
- package/dist/tools/documentation/simple-pdf-indexer.d.ts +1 -0
- package/dist/tools/documentation/simple-pdf-indexer.d.ts.map +1 -0
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/interactions/click.d.ts +2 -1
- package/dist/tools/interactions/click.d.ts.map +1 -0
- package/dist/tools/interactions/click.js +4 -2
- package/dist/tools/interactions/click.js.map +1 -1
- package/dist/tools/interactions/double-tap.d.ts +2 -1
- package/dist/tools/interactions/double-tap.d.ts.map +1 -0
- package/dist/tools/interactions/double-tap.js +8 -4
- package/dist/tools/interactions/double-tap.js.map +1 -1
- package/dist/tools/interactions/drag-and-drop.d.ts +2 -1
- package/dist/tools/interactions/drag-and-drop.d.ts.map +1 -0
- package/dist/tools/interactions/drag-and-drop.js +4 -4
- package/dist/tools/interactions/drag-and-drop.js.map +1 -1
- package/dist/tools/interactions/find.d.ts +2 -1
- package/dist/tools/interactions/find.d.ts.map +1 -0
- package/dist/tools/interactions/find.js.map +1 -1
- package/dist/tools/interactions/get-page-source.d.ts +2 -1
- package/dist/tools/interactions/get-page-source.d.ts.map +1 -0
- package/dist/tools/interactions/get-page-source.js.map +1 -1
- package/dist/tools/interactions/get-text.d.ts +2 -1
- package/dist/tools/interactions/get-text.d.ts.map +1 -0
- package/dist/tools/interactions/get-text.js +4 -2
- package/dist/tools/interactions/get-text.js.map +1 -1
- package/dist/tools/interactions/long-press.d.ts +2 -1
- package/dist/tools/interactions/long-press.d.ts.map +1 -0
- package/dist/tools/interactions/long-press.js +12 -5
- package/dist/tools/interactions/long-press.js.map +1 -1
- package/dist/tools/interactions/screenshot.d.ts +6 -4
- package/dist/tools/interactions/screenshot.d.ts.map +1 -0
- package/dist/tools/interactions/screenshot.js +6 -3
- package/dist/tools/interactions/screenshot.js.map +1 -1
- package/dist/tools/interactions/set-value.d.ts +2 -1
- package/dist/tools/interactions/set-value.d.ts.map +1 -0
- package/dist/tools/interactions/set-value.js +4 -2
- package/dist/tools/interactions/set-value.js.map +1 -1
- package/dist/tools/ios/boot-simulator.d.ts +1 -0
- package/dist/tools/ios/boot-simulator.d.ts.map +1 -0
- package/dist/tools/ios/install-wda.d.ts +1 -0
- package/dist/tools/ios/install-wda.d.ts.map +1 -0
- package/dist/tools/ios/setup-wda.d.ts +1 -0
- package/dist/tools/ios/setup-wda.d.ts.map +1 -0
- package/dist/tools/navigations/scroll-to-element.d.ts +1 -0
- package/dist/tools/navigations/scroll-to-element.d.ts.map +1 -0
- package/dist/tools/navigations/scroll-to-element.js +2 -2
- package/dist/tools/navigations/scroll-to-element.js.map +1 -1
- package/dist/tools/navigations/scroll.d.ts +1 -0
- package/dist/tools/navigations/scroll.d.ts.map +1 -0
- package/dist/tools/navigations/scroll.js +19 -9
- package/dist/tools/navigations/scroll.js.map +1 -1
- package/dist/tools/navigations/swipe.d.ts +1 -0
- package/dist/tools/navigations/swipe.d.ts.map +1 -0
- package/dist/tools/navigations/swipe.js +11 -5
- package/dist/tools/navigations/swipe.js.map +1 -1
- package/dist/tools/session/create-session.d.ts +31 -0
- package/dist/tools/session/create-session.d.ts.map +1 -0
- package/dist/tools/session/create-session.js +88 -21
- package/dist/tools/session/create-session.js.map +1 -1
- package/dist/tools/session/delete-session.d.ts +1 -0
- package/dist/tools/session/delete-session.d.ts.map +1 -0
- package/dist/tools/session/delete-session.js +10 -1
- package/dist/tools/session/delete-session.js.map +1 -1
- package/dist/tools/session/select-device.d.ts +1 -0
- package/dist/tools/session/select-device.d.ts.map +1 -0
- package/dist/tools/session/select-device.js +11 -4
- package/dist/tools/session/select-device.js.map +1 -1
- package/dist/tools/session/select-platform.d.ts +1 -0
- package/dist/tools/session/select-platform.d.ts.map +1 -0
- package/dist/tools/session/select-platform.js +12 -5
- package/dist/tools/session/select-platform.js.map +1 -1
- package/dist/tools/test-generation/generate-tests.d.ts +2 -1
- package/dist/tools/test-generation/generate-tests.d.ts.map +1 -0
- package/dist/tools/test-generation/locators.d.ts +1 -0
- package/dist/tools/test-generation/locators.d.ts.map +1 -0
- package/dist/tools/test-generation/locators.js +4 -2
- package/dist/tools/test-generation/locators.js.map +1 -1
- package/dist/ui/mcp-ui-utils.d.ts +1 -0
- package/dist/ui/mcp-ui-utils.d.ts.map +1 -0
- package/package.json +6 -6
- package/server.json +2 -2
- package/src/session-store.ts +34 -2
- package/src/tests/screenshot.test.ts +6 -5
- package/src/tools/app-management/activate-app.ts +2 -2
- package/src/tools/app-management/install-app.ts +12 -3
- package/src/tools/app-management/list-apps.ts +12 -3
- package/src/tools/app-management/terminate-app.ts +12 -3
- package/src/tools/app-management/uninstall-app.ts +12 -3
- package/src/tools/context/get-contexts.ts +10 -4
- package/src/tools/context/switch-context.ts +17 -6
- package/src/tools/index.ts +1 -1
- package/src/tools/interactions/click.ts +6 -3
- package/src/tools/interactions/double-tap.ts +19 -7
- package/src/tools/interactions/drag-and-drop.ts +16 -7
- package/src/tools/interactions/find.ts +5 -2
- package/src/tools/interactions/get-page-source.ts +2 -2
- package/src/tools/interactions/get-text.ts +6 -3
- package/src/tools/interactions/long-press.ts +22 -10
- package/src/tools/interactions/screenshot.ts +11 -5
- package/src/tools/interactions/set-value.ts +9 -3
- package/src/tools/navigations/scroll-to-element.ts +4 -4
- package/src/tools/navigations/scroll.ts +25 -10
- package/src/tools/navigations/swipe.ts +17 -6
- package/src/tools/session/create-session.ts +108 -27
- package/src/tools/session/delete-session.ts +10 -1
- package/src/tools/session/select-device.ts +11 -4
- package/src/tools/session/select-platform.ts +12 -5
- package/src/tools/test-generation/generate-tests.ts +1 -1
- package/src/tools/test-generation/locators.ts +8 -3
- package/tsconfig.json +7 -15
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getDriver,
|
|
5
|
+
getPlatformName,
|
|
6
|
+
isRemoteDriverSession,
|
|
7
|
+
PLATFORM,
|
|
8
|
+
} from '../../session-store.js';
|
|
4
9
|
|
|
5
10
|
export default function switchContext(server: FastMCP): void {
|
|
6
11
|
const schema = z.object({
|
|
@@ -26,10 +31,16 @@ export default function switchContext(server: FastMCP): void {
|
|
|
26
31
|
throw new Error('No driver found. Please create a session first.');
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
if (isRemoteDriverSession(driver)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
'Get context is not yet implemented for the remote driver'
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
try {
|
|
30
41
|
const [currentContext, availableContexts] = await Promise.all([
|
|
31
|
-
driver.getCurrentContext().catch(() => null),
|
|
32
|
-
driver.getContexts().catch(() => []),
|
|
42
|
+
(driver as any).getCurrentContext().catch(() => null),
|
|
43
|
+
(driver as any).getContexts().catch(() => []),
|
|
33
44
|
]);
|
|
34
45
|
|
|
35
46
|
if (currentContext === args.context) {
|
|
@@ -66,10 +77,10 @@ export default function switchContext(server: FastMCP): void {
|
|
|
66
77
|
isError: true,
|
|
67
78
|
};
|
|
68
79
|
}
|
|
69
|
-
await driver.switchContext(args.context);
|
|
80
|
+
await (driver as any).switchContext(args.context);
|
|
70
81
|
|
|
71
82
|
// Verify the switch was successful
|
|
72
|
-
const newContext = await driver.getCurrentContext();
|
|
83
|
+
const newContext = await (driver as any).getCurrentContext();
|
|
73
84
|
|
|
74
85
|
return {
|
|
75
86
|
content: [
|
package/src/tools/index.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* See src/tools/README.md for tool organization.
|
|
13
13
|
* See src/tools/metadata/README.md for YAML metadata approach.
|
|
14
14
|
*/
|
|
15
|
-
import { FastMCP } from 'fastmcp
|
|
15
|
+
import { FastMCP } from 'fastmcp';
|
|
16
16
|
import log from '../logger.js';
|
|
17
17
|
import answerAppium from './documentation/answer-appium.js';
|
|
18
18
|
import createSession from './session/create-session.js';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getDriver } from '../../session-store.js';
|
|
3
|
+
import { getDriver, isRemoteDriverSession } from '../../session-store.js';
|
|
4
4
|
import { elementUUIDScheme } from '../../schema.js';
|
|
5
|
+
import type { Client } from 'webdriver';
|
|
5
6
|
|
|
6
7
|
export default function generateTest(server: FastMCP): void {
|
|
7
8
|
const clickActionSchema = z.object({
|
|
@@ -23,7 +24,9 @@ export default function generateTest(server: FastMCP): void {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
try {
|
|
26
|
-
|
|
27
|
+
const _ok = isRemoteDriverSession(driver)
|
|
28
|
+
? await (driver as Client).elementClick(args.elementUUID)
|
|
29
|
+
: await (driver as any).click(args.elementUUID);
|
|
27
30
|
return {
|
|
28
31
|
content: [
|
|
29
32
|
{
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getDriver,
|
|
5
|
+
getPlatformName,
|
|
6
|
+
isRemoteDriverSession,
|
|
7
|
+
} from '../../session-store.js';
|
|
4
8
|
import { elementUUIDScheme } from '../../schema.js';
|
|
9
|
+
import type { Client } from 'webdriver';
|
|
5
10
|
|
|
6
11
|
export default function doubleTap(server: FastMCP): void {
|
|
7
12
|
const doubleTapActionSchema = z.object({
|
|
@@ -27,7 +32,10 @@ export default function doubleTap(server: FastMCP): void {
|
|
|
27
32
|
|
|
28
33
|
if (platform === 'Android') {
|
|
29
34
|
// Get element location for Android double tap
|
|
30
|
-
const element = await driver.findElement(
|
|
35
|
+
const element = await (driver as any).findElement(
|
|
36
|
+
'id',
|
|
37
|
+
args.elementUUID
|
|
38
|
+
);
|
|
31
39
|
const location = await element.getLocation();
|
|
32
40
|
const size = await element.getSize();
|
|
33
41
|
|
|
@@ -36,7 +44,7 @@ export default function doubleTap(server: FastMCP): void {
|
|
|
36
44
|
const y = location.y + size.height / 2;
|
|
37
45
|
|
|
38
46
|
// Perform double tap using performActions
|
|
39
|
-
await driver.performActions([
|
|
47
|
+
await (driver as any).performActions([
|
|
40
48
|
{
|
|
41
49
|
type: 'pointer',
|
|
42
50
|
id: 'finger1',
|
|
@@ -55,9 +63,13 @@ export default function doubleTap(server: FastMCP): void {
|
|
|
55
63
|
]);
|
|
56
64
|
} else if (platform === 'iOS') {
|
|
57
65
|
// Use iOS mobile: doubleTap execute method
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
const _ok = isRemoteDriverSession(driver)
|
|
67
|
+
? await (driver as Client).executeScript('mobile: doubleTap', [
|
|
68
|
+
{ elementId: args.elementUUID },
|
|
69
|
+
])
|
|
70
|
+
: await (driver as any).execute('mobile: doubleTap', [
|
|
71
|
+
{ elementId: args.elementUUID },
|
|
72
|
+
]);
|
|
61
73
|
} else {
|
|
62
74
|
throw new Error(
|
|
63
75
|
`Unsupported platform: ${platform}. Only Android and iOS are supported.`
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getDriver,
|
|
5
|
+
getPlatformName,
|
|
6
|
+
isRemoteDriverSession,
|
|
7
|
+
} from '../../session-store.js';
|
|
4
8
|
import { elementUUIDScheme } from '../../schema.js';
|
|
9
|
+
import type { Client } from 'webdriver';
|
|
5
10
|
|
|
6
11
|
const DROP_PAUSE_DURATION_MS = 150;
|
|
7
12
|
|
|
@@ -108,13 +113,13 @@ export default function dragAndDrop(server: FastMCP): void {
|
|
|
108
113
|
1. Long press (default 600ms, configurable) on the source to initiate drag mode
|
|
109
114
|
2. While holding, drag to the target location
|
|
110
115
|
3. Release at the target to complete the drop
|
|
111
|
-
|
|
116
|
+
|
|
112
117
|
Supports four modes:
|
|
113
118
|
1. Element to Element: Drag from one element to another element
|
|
114
119
|
2. Element to Coordinates: Drag from an element to specific coordinates
|
|
115
120
|
3. Coordinates to Element: Drag from coordinates to an element
|
|
116
121
|
4. Coordinates to Coordinates: Drag from coordinates to coordinates
|
|
117
|
-
|
|
122
|
+
|
|
118
123
|
This is useful for reordering lists, moving items, drag-to-delete, and other drag interactions.`,
|
|
119
124
|
parameters: dragAndDropSchema,
|
|
120
125
|
annotations: {
|
|
@@ -154,7 +159,9 @@ export default function dragAndDrop(server: FastMCP): void {
|
|
|
154
159
|
let endX: number, endY: number;
|
|
155
160
|
|
|
156
161
|
if (args.sourceElementUUID) {
|
|
157
|
-
const rect = await driver.getElementRect(
|
|
162
|
+
const rect = await (driver as any).getElementRect(
|
|
163
|
+
args.sourceElementUUID
|
|
164
|
+
);
|
|
158
165
|
startX = Math.floor(rect.x + rect.width / 2);
|
|
159
166
|
startY = Math.floor(rect.y + rect.height / 2);
|
|
160
167
|
} else {
|
|
@@ -163,7 +170,9 @@ export default function dragAndDrop(server: FastMCP): void {
|
|
|
163
170
|
}
|
|
164
171
|
|
|
165
172
|
if (args.targetElementUUID) {
|
|
166
|
-
const rect = await driver.getElementRect(
|
|
173
|
+
const rect = await (driver as any).getElementRect(
|
|
174
|
+
args.targetElementUUID
|
|
175
|
+
);
|
|
167
176
|
endX = Math.floor(rect.x + rect.width / 2);
|
|
168
177
|
endY = Math.floor(rect.y + rect.height / 2);
|
|
169
178
|
} else {
|
|
@@ -171,7 +180,7 @@ export default function dragAndDrop(server: FastMCP): void {
|
|
|
171
180
|
endY = args.targetY;
|
|
172
181
|
}
|
|
173
182
|
|
|
174
|
-
const { width, height } = await driver.
|
|
183
|
+
const { width, height } = await (driver as any).getWindowRect();
|
|
175
184
|
if (startX < 0 || startX >= width || startY < 0 || startY >= height) {
|
|
176
185
|
throw new Error(
|
|
177
186
|
`Source coordinates (${startX}, ${startY}) are out of screen bounds (${width}x${height})`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { getDriver } from '../../session-store.js';
|
|
4
4
|
|
|
@@ -34,7 +34,10 @@ export default function findElement(server: FastMCP): void {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
try {
|
|
37
|
-
const element = await driver.findElement(
|
|
37
|
+
const element = await (driver as any).findElement(
|
|
38
|
+
args.strategy,
|
|
39
|
+
args.selector
|
|
40
|
+
);
|
|
38
41
|
return {
|
|
39
42
|
content: [
|
|
40
43
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { getDriver } from '../../session-store.js';
|
|
4
4
|
import {
|
|
@@ -23,7 +23,7 @@ export default function getPageSource(server: FastMCP): void {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
try {
|
|
26
|
-
const pageSource = await driver.getPageSource();
|
|
26
|
+
const pageSource = await (driver as any).getPageSource();
|
|
27
27
|
|
|
28
28
|
if (!pageSource) {
|
|
29
29
|
throw new Error('Page source is empty or null');
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getDriver } from '../../session-store.js';
|
|
3
|
+
import { getDriver, isRemoteDriverSession } from '../../session-store.js';
|
|
4
4
|
import { elementUUIDScheme } from '../../schema.js';
|
|
5
|
+
import type { Client } from 'webdriver';
|
|
5
6
|
|
|
6
7
|
export default function getText(server: FastMCP): void {
|
|
7
8
|
const getTextSchema = z.object({
|
|
@@ -23,7 +24,9 @@ export default function getText(server: FastMCP): void {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
try {
|
|
26
|
-
const text =
|
|
27
|
+
const text = isRemoteDriverSession(driver)
|
|
28
|
+
? await (driver as Client).getElementText(args.elementUUID)
|
|
29
|
+
: await (driver as any).getText(args.elementUUID);
|
|
27
30
|
return {
|
|
28
31
|
content: [
|
|
29
32
|
{
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getDriver,
|
|
5
|
+
getPlatformName,
|
|
6
|
+
isRemoteDriverSession,
|
|
7
|
+
} from '../../session-store.js';
|
|
4
8
|
import { elementUUIDScheme } from '../../schema.js';
|
|
9
|
+
import type { Client } from 'webdriver';
|
|
5
10
|
|
|
6
11
|
export default function longPress(server: FastMCP): void {
|
|
7
12
|
const longPressSchema = z.object({
|
|
@@ -37,11 +42,11 @@ export default function longPress(server: FastMCP): void {
|
|
|
37
42
|
const duration = args.duration || 2000;
|
|
38
43
|
|
|
39
44
|
if (platform === 'Android') {
|
|
40
|
-
const rect = await driver.getElementRect(args.elementUUID);
|
|
45
|
+
const rect = await (driver as any).getElementRect(args.elementUUID);
|
|
41
46
|
const x = Math.floor(rect.x + rect.width / 2);
|
|
42
47
|
const y = Math.floor(rect.y + rect.height / 2);
|
|
43
48
|
|
|
44
|
-
await driver.performActions([
|
|
49
|
+
await (driver as any).performActions([
|
|
45
50
|
{
|
|
46
51
|
type: 'pointer',
|
|
47
52
|
id: 'finger1',
|
|
@@ -56,16 +61,23 @@ export default function longPress(server: FastMCP): void {
|
|
|
56
61
|
]);
|
|
57
62
|
} else if (platform === 'iOS') {
|
|
58
63
|
try {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
const _ok = isRemoteDriverSession(driver)
|
|
65
|
+
? await (driver as Client).executeScript('mobile: touchAndHold', [
|
|
66
|
+
{
|
|
67
|
+
elementId: args.elementUUID,
|
|
68
|
+
duration: duration / 1000,
|
|
69
|
+
},
|
|
70
|
+
])
|
|
71
|
+
: await (driver as any).execute('mobile: touchAndHold', {
|
|
72
|
+
elementId: args.elementUUID,
|
|
73
|
+
duration: duration / 1000,
|
|
74
|
+
});
|
|
63
75
|
} catch (touchAndHoldError) {
|
|
64
|
-
const rect = await driver.getElementRect(args.elementUUID);
|
|
76
|
+
const rect = await (driver as any).getElementRect(args.elementUUID);
|
|
65
77
|
const x = Math.floor(rect.x + rect.width / 2);
|
|
66
78
|
const y = Math.floor(rect.y + rect.height / 2);
|
|
67
79
|
|
|
68
|
-
await driver.performActions([
|
|
80
|
+
await (driver as any).performActions([
|
|
69
81
|
{
|
|
70
82
|
type: 'pointer',
|
|
71
83
|
id: 'finger1',
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
2
|
-
import { getDriver } from '../../session-store.js';
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
|
+
import { getDriver, isRemoteDriverSession } from '../../session-store.js';
|
|
3
3
|
import { writeFile, mkdir } from 'fs/promises';
|
|
4
4
|
import { join, isAbsolute } from 'path';
|
|
5
|
+
import * as os from 'node:os';
|
|
5
6
|
import {
|
|
6
7
|
createUIResource,
|
|
7
8
|
createScreenshotViewerUI,
|
|
8
9
|
addUIResourceToResponse,
|
|
9
10
|
} from '../../ui/mcp-ui-utils.js';
|
|
11
|
+
import type { Client } from 'webdriver';
|
|
12
|
+
import type { XCUITestDriver } from 'appium-xcuitest-driver';
|
|
13
|
+
import type { AndroidUiautomator2Driver } from 'appium-uiautomator2-driver';
|
|
10
14
|
|
|
11
15
|
/**
|
|
12
16
|
* Resolves the screenshot directory path.
|
|
@@ -18,7 +22,7 @@ export function resolveScreenshotDir(): string {
|
|
|
18
22
|
const screenshotDir = process.env.SCREENSHOTS_DIR;
|
|
19
23
|
|
|
20
24
|
if (!screenshotDir) {
|
|
21
|
-
return
|
|
25
|
+
return os.tmpdir();
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
if (isAbsolute(screenshotDir)) {
|
|
@@ -29,7 +33,7 @@ export function resolveScreenshotDir(): string {
|
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
export interface ScreenshotDeps {
|
|
32
|
-
getDriver: () =>
|
|
36
|
+
getDriver: () => Client | AndroidUiautomator2Driver | XCUITestDriver | null;
|
|
33
37
|
writeFile: typeof writeFile;
|
|
34
38
|
mkdir: typeof mkdir;
|
|
35
39
|
resolveScreenshotDir: typeof resolveScreenshotDir;
|
|
@@ -53,7 +57,9 @@ export async function executeScreenshot(
|
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
try {
|
|
56
|
-
const screenshotBase64 =
|
|
60
|
+
const screenshotBase64 = isRemoteDriverSession(driver)
|
|
61
|
+
? await (driver as Client).takeScreenshot()
|
|
62
|
+
: await (driver as any).getScreenshot();
|
|
57
63
|
|
|
58
64
|
// Convert base64 to buffer
|
|
59
65
|
const screenshotBuffer = Buffer.from(screenshotBase64, 'base64');
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { FastMCP } from 'fastmcp
|
|
1
|
+
import { FastMCP } from 'fastmcp';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { getDriver } from '../../session-store.js';
|
|
3
|
+
import { getDriver, isRemoteDriverSession } from '../../session-store.js';
|
|
4
4
|
import { elementUUIDScheme } from '../../schema.js';
|
|
5
|
+
import type { Client } from 'webdriver';
|
|
5
6
|
|
|
6
7
|
export default function setValue(server: FastMCP): void {
|
|
7
8
|
const setValueSchema = z.object({
|
|
@@ -24,7 +25,12 @@ export default function setValue(server: FastMCP): void {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
try {
|
|
27
|
-
|
|
28
|
+
const _ok = isRemoteDriverSession(driver)
|
|
29
|
+
? await (driver as Client).elementSendKeys(
|
|
30
|
+
args.elementUUID,
|
|
31
|
+
args.text
|
|
32
|
+
)
|
|
33
|
+
: await (driver as any).setValue(args.text, args.elementUUID);
|
|
28
34
|
return {
|
|
29
35
|
content: [
|
|
30
36
|
{
|
|
@@ -84,7 +84,7 @@ async function performAndroidScroll(
|
|
|
84
84
|
await driver.findElement('-android uiautomator', scrollCommand);
|
|
85
85
|
} catch (error) {
|
|
86
86
|
// If UiScrollable fails, try touch actions
|
|
87
|
-
const { width, height } = await driver.
|
|
87
|
+
const { width, height } = await driver.getWindowRect();
|
|
88
88
|
const startX = width / 2;
|
|
89
89
|
const startY = direction === 'up' ? height * 0.3 : height * 0.7;
|
|
90
90
|
const endY = direction === 'up' ? height * 0.7 : height * 0.3;
|
|
@@ -100,7 +100,7 @@ async function performAndroidScroll(
|
|
|
100
100
|
|
|
101
101
|
async function performiOSScroll(driver: any, direction: string): Promise<void> {
|
|
102
102
|
// Use iOS mobile commands for scrolling
|
|
103
|
-
const { width, height } = await driver.
|
|
103
|
+
const { width, height } = await driver.getWindowRect();
|
|
104
104
|
|
|
105
105
|
await driver.execute('mobile: scroll', {
|
|
106
106
|
direction: direction,
|
|
@@ -133,7 +133,7 @@ export default function scrollToElement(server: any): void {
|
|
|
133
133
|
|
|
134
134
|
// First try to find the element directly (it might already be in viewport)
|
|
135
135
|
try {
|
|
136
|
-
const element = await driver.findElement(
|
|
136
|
+
const element = await (driver as any).findElement(
|
|
137
137
|
args.strategy,
|
|
138
138
|
args.selector
|
|
139
139
|
);
|
|
@@ -160,7 +160,7 @@ export default function scrollToElement(server: any): void {
|
|
|
160
160
|
);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
const element = await driver.findElement(
|
|
163
|
+
const element = await (driver as any).findElement(
|
|
164
164
|
args.strategy,
|
|
165
165
|
args.selector
|
|
166
166
|
);
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getDriver,
|
|
4
|
+
getPlatformName,
|
|
5
|
+
isRemoteDriverSession,
|
|
6
|
+
} from '../../session-store.js';
|
|
3
7
|
import log from '../../logger.js';
|
|
8
|
+
import type { Client } from 'webdriver';
|
|
4
9
|
|
|
5
10
|
export default function scroll(server: any): void {
|
|
6
11
|
server.addTool({
|
|
@@ -25,7 +30,7 @@ export default function scroll(server: any): void {
|
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
try {
|
|
28
|
-
const { width, height } = await driver.
|
|
33
|
+
const { width, height } = await (driver as any).getWindowRect();
|
|
29
34
|
log.info('Device screen size:', { width, height });
|
|
30
35
|
const startX = Math.floor(width / 2);
|
|
31
36
|
// calculate start and end Y positions for scrolling depending on the direction
|
|
@@ -47,7 +52,7 @@ export default function scroll(server: any): void {
|
|
|
47
52
|
log.info('Going to scroll to:', { startX, endY });
|
|
48
53
|
|
|
49
54
|
if (getPlatformName(driver) === 'Android') {
|
|
50
|
-
await driver.performActions([
|
|
55
|
+
await (driver as any).performActions([
|
|
51
56
|
{
|
|
52
57
|
type: 'pointer',
|
|
53
58
|
id: 'finger1',
|
|
@@ -63,13 +68,23 @@ export default function scroll(server: any): void {
|
|
|
63
68
|
]);
|
|
64
69
|
log.info('Scroll action completed successfully.');
|
|
65
70
|
} else if (getPlatformName(driver) === 'iOS') {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
const _ok = isRemoteDriverSession(driver)
|
|
72
|
+
? await (driver as Client).executeScript('mobile: scroll', [
|
|
73
|
+
{
|
|
74
|
+
direction: args.direction,
|
|
75
|
+
startX: startX,
|
|
76
|
+
startY: startY,
|
|
77
|
+
endX: startX,
|
|
78
|
+
endY: endY,
|
|
79
|
+
},
|
|
80
|
+
])
|
|
81
|
+
: await (driver as any).execute('mobile: scroll', {
|
|
82
|
+
direction: args.direction,
|
|
83
|
+
startX: startX,
|
|
84
|
+
startY: startY,
|
|
85
|
+
endX: startX,
|
|
86
|
+
endY: endY,
|
|
87
|
+
});
|
|
73
88
|
} else {
|
|
74
89
|
throw new Error(
|
|
75
90
|
`Unsupported platform: ${getPlatformName(driver)}. Only Android and iOS are supported.`
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getDriver,
|
|
4
|
+
getPlatformName,
|
|
5
|
+
isRemoteDriverSession,
|
|
6
|
+
} from '../../session-store.js';
|
|
3
7
|
import log from '../../logger.js';
|
|
4
8
|
import { elementUUIDScheme } from '../../schema.js';
|
|
9
|
+
import type { Client } from 'webdriver';
|
|
5
10
|
|
|
6
11
|
function calculateSwipeCoordinates(
|
|
7
12
|
direction: 'left' | 'right' | 'up' | 'down',
|
|
@@ -227,7 +232,7 @@ export default function swipe(server: any): void {
|
|
|
227
232
|
endY,
|
|
228
233
|
});
|
|
229
234
|
} else {
|
|
230
|
-
const { width, height } = await driver.
|
|
235
|
+
const { width, height } = await (driver as any).getWindowRect();
|
|
231
236
|
log.info('Device screen size:', { width, height });
|
|
232
237
|
const coords = calculateSwipeCoordinates(
|
|
233
238
|
args.direction,
|
|
@@ -268,7 +273,7 @@ export default function swipe(server: any): void {
|
|
|
268
273
|
if (platform === 'Android') {
|
|
269
274
|
if (startX !== endX && Math.abs(startY - endY) < 50) {
|
|
270
275
|
const swipeDuration = Math.min(duration, 400);
|
|
271
|
-
await driver.performActions([
|
|
276
|
+
await (driver as any).performActions([
|
|
272
277
|
{
|
|
273
278
|
type: 'pointer',
|
|
274
279
|
id: 'finger1',
|
|
@@ -303,9 +308,15 @@ export default function swipe(server: any): void {
|
|
|
303
308
|
} else if (platform === 'iOS') {
|
|
304
309
|
if (args.direction) {
|
|
305
310
|
try {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
311
|
+
const _ok = isRemoteDriverSession(driver)
|
|
312
|
+
? await (driver as Client).executeScript('mobile: swipe', [
|
|
313
|
+
{
|
|
314
|
+
direction: args.direction,
|
|
315
|
+
},
|
|
316
|
+
])
|
|
317
|
+
: await (driver as any).execute('mobile: swipe', {
|
|
318
|
+
direction: args.direction,
|
|
319
|
+
});
|
|
309
320
|
log.info(
|
|
310
321
|
`iOS swipe completed using mobile: swipe (${args.direction})`
|
|
311
322
|
);
|