Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ MCP Appium provides a comprehensive set of tools organized into the following ca
| `appium_find_element` | Find a specific element using various locator strategies (xpath, id, accessibility id, etc.) |
| `appium_click` | Click on an element |
| `appium_double_tap` | Perform double tap on an element |
| `appium_long_press` | Perform a long press (press and hold) gesture on an element |
| `appium_set_value` | Enter text into an input field |
| `appium_get_text` | Get text content from an element |

Expand Down
1 change: 1 addition & 0 deletions src/tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This directory contains all MCP tools available in MCP Appium.
- `find.ts` - Find elements
- `click.ts` - Click elements
- `double-tap.ts` - Double tap elements
- `long-press.ts` - Long press (press and hold) elements
- `set-value.ts` - Enter text
- `get-text.ts` - Get element text
- `get-page-source.ts` - Get page source (XML) from current screen
Expand Down
2 changes: 2 additions & 0 deletions src/tools/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import swipe from './navigations/swipe.js';
import findElement from './interactions/find.js';
import clickElement from './interactions/click.js';
import doubleTap from './interactions/double-tap.js';
import longPress from './interactions/long-press.js';
import setValue from './interactions/set-value.js';
import getText from './interactions/get-text.js';
import getPageSource from './interactions/get-page-source.js';
Expand Down Expand Up @@ -129,6 +130,7 @@ export default function registerTools(server: FastMCP): void {
findElement(server);
clickElement(server);
doubleTap(server);
longPress(server);
setValue(server);
getText(server);
getPageSource(server);
Expand Down
108 changes: 108 additions & 0 deletions src/tools/interactions/long-press.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { FastMCP } from 'fastmcp/dist/FastMCP.js';
import { z } from 'zod';
import { getDriver, getPlatformName } from '../../session-store.js';
import { elementUUIDScheme } from '../../schema.js';

export default function longPress(server: FastMCP): void {
const longPressSchema = z.object({
elementUUID: elementUUIDScheme,
duration: z
.number()
.int()
.min(500)
.max(10000)
.default(2000)
.optional()
.describe(
'Duration of the long press in milliseconds. Default is 2000ms.'
),
});

server.addTool({
name: 'appium_long_press',
description: 'Perform a long press (press and hold) gesture on an element',
parameters: longPressSchema,
annotations: {
readOnlyHint: false,
openWorldHint: false,
},
execute: async (args: any, context: any): Promise<any> => {
const driver = getDriver();
if (!driver) {
throw new Error('No driver found');
}

try {
const platform = getPlatformName(driver);
const duration = args.duration || 2000;

if (platform === 'Android') {
const rect = await driver.getElementRect(args.elementUUID);
const x = Math.floor(rect.x + rect.width / 2);
const y = Math.floor(rect.y + rect.height / 2);

await driver.performActions([
{
type: 'pointer',
id: 'finger1',
parameters: { pointerType: 'touch' },
actions: [
{ type: 'pointerMove', duration: 0, x, y },
{ type: 'pointerDown', button: 0 },
{ type: 'pause', duration: duration },
{ type: 'pointerUp', button: 0 },
],
},
]);
} else if (platform === 'iOS') {
try {
await driver.execute('mobile: touchAndHold', {
elementId: args.elementUUID,
duration: duration / 1000,
});
} catch (touchAndHoldError) {
const rect = await driver.getElementRect(args.elementUUID);
const x = Math.floor(rect.x + rect.width / 2);
const y = Math.floor(rect.y + rect.height / 2);

await driver.performActions([
{
type: 'pointer',
id: 'finger1',
parameters: { pointerType: 'touch' },
actions: [
{ type: 'pointerMove', duration: 0, x, y },
{ type: 'pointerDown', button: 0 },
{ type: 'pause', duration: duration },
{ type: 'pointerUp', button: 0 },
],
},
]);
}
} else {
throw new Error(
`Unsupported platform: ${platform}. Only Android and iOS are supported.`
);
}

return {
content: [
{
type: 'text',
text: `Successfully performed long press on element ${args.elementUUID}`,
},
],
};
} catch (err: any) {
return {
content: [
{
type: 'text',
text: `Failed to perform long press on element ${args.elementUUID}. err: ${err.toString()}`,
},
],
};
}
},
});
}