appium-mcp 1.69.1 → 1.70.0
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/CHANGELOG.md +6 -0
- package/README.md +1 -2
- package/dist/tools/interactions/keyboard.d.ts.map +1 -1
- package/dist/tools/interactions/keyboard.js +48 -56
- package/dist/tools/interactions/keyboard.js.map +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/src/resources/submodules.zip +0 -0
- package/src/tools/README.md +1 -1
- package/src/tools/interactions/keyboard.ts +62 -70
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [1.70.0](https://github.com/appium/appium-mcp/compare/v1.69.1...v1.70.0) (2026-04-29)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **tools:** single appium_mobile_keyboard tool ([#293](https://github.com/appium/appium-mcp/issues/293)) ([1214950](https://github.com/appium/appium-mcp/commit/1214950819b1b9edc4c73c9ea2ebc120da91ad7b))
|
|
6
|
+
|
|
1
7
|
## [1.69.1](https://github.com/appium/appium-mcp/compare/v1.69.0...v1.69.1) (2026-04-29)
|
|
2
8
|
|
|
3
9
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -341,8 +341,7 @@ The default regex pattern allows any URL that starts with `http://` or `https://
|
|
|
341
341
|
| `appium_drag_and_drop` | Perform a drag and drop gesture from a source location to a target location (supports element-to-element, element-to-coordinates, coordinates-to-element, and coordinates-to-coordinates) |
|
|
342
342
|
| `appium_perform_actions` | Execute raw W3C Actions API sequences for custom multi-touch gestures (rotate, three-finger swipe, edge swipes, precise timing). Prefer `appium_gesture` for standard gestures. |
|
|
343
343
|
| `appium_set_value` | Enter text into an input field |
|
|
344
|
-
| `
|
|
345
|
-
| `appium_mobile_is_keyboard_shown` | Whether the on-screen keyboard is visible (`mobile: isKeyboardShown`) |
|
|
344
|
+
| `appium_mobile_keyboard` | Hide the on-screen keyboard or query visibility. `action=hide` \| `is_shown` (`keys` optional for hide). |
|
|
346
345
|
| `appium_get_text` | Get text content from an element |
|
|
347
346
|
| `appium_mobile_clipboard` | Read or set device clipboard plain text. `action=get` \| `set` (`content` required for set). |
|
|
348
347
|
| `appium_alert` | Handle alerts with `action` = `accept`, `dismiss`, or `get_text` (optional `buttonLabel`) |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/tools/interactions/keyboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/tools/interactions/keyboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,OAAO,EAAE,MAAM,SAAS,CAAC;AA0DtD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAiCtD"}
|
|
@@ -1,73 +1,65 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { execute } from '../../command.js';
|
|
3
3
|
import { resolveDriver, textResult, errorResult, toolErrorMessage, } from '../tool-response.js';
|
|
4
|
+
const schema = z.object({
|
|
5
|
+
action: z
|
|
6
|
+
.enum(['hide', 'is_shown'])
|
|
7
|
+
.describe('hide: dismiss the software keyboard (mobile: hideKeyboard). ' +
|
|
8
|
+
'is_shown: whether the keyboard is visible (mobile: isKeyboardShown).'),
|
|
9
|
+
keys: z
|
|
10
|
+
.array(z.string())
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('hide only: optional key names to dismiss the keyboard (e.g. "done"). ' +
|
|
13
|
+
'Forwarded to mobile: hideKeyboard when non-empty. Ignored for is_shown.'),
|
|
14
|
+
sessionId: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Session ID to target. If omitted, uses the active session.'),
|
|
18
|
+
});
|
|
19
|
+
async function handleHide(sessionId, keys) {
|
|
20
|
+
const resolved = resolveDriver(sessionId);
|
|
21
|
+
if (!resolved.ok) {
|
|
22
|
+
return resolved.result;
|
|
23
|
+
}
|
|
24
|
+
const { driver } = resolved;
|
|
25
|
+
const params = keys && keys.length > 0 ? { keys } : {};
|
|
26
|
+
await execute(driver, 'mobile: hideKeyboard', params);
|
|
27
|
+
return textResult('Keyboard dismissed successfully.');
|
|
28
|
+
}
|
|
29
|
+
async function handleIsShown(sessionId) {
|
|
30
|
+
const resolved = resolveDriver(sessionId);
|
|
31
|
+
if (!resolved.ok) {
|
|
32
|
+
return resolved.result;
|
|
33
|
+
}
|
|
34
|
+
const { driver } = resolved;
|
|
35
|
+
const keyboardShown = await execute(driver, 'mobile: isKeyboardShown', {});
|
|
36
|
+
return textResult(JSON.stringify({ keyboardShown }, null, 2));
|
|
37
|
+
}
|
|
4
38
|
export default function keyboard(server) {
|
|
5
|
-
const hideKeyboardSchema = z.object({
|
|
6
|
-
keys: z
|
|
7
|
-
.array(z.string())
|
|
8
|
-
.optional()
|
|
9
|
-
.describe('Optional key names used to dismiss the keyboard (e.g. "done" on tablets). ' +
|
|
10
|
-
'Maps to the `keys` argument of mobile: hideKeyboard. Omit for default behavior.'),
|
|
11
|
-
sessionId: z
|
|
12
|
-
.string()
|
|
13
|
-
.optional()
|
|
14
|
-
.describe('Session ID to target. If omitted, uses the active session.'),
|
|
15
|
-
});
|
|
16
39
|
server.addTool({
|
|
17
|
-
name: '
|
|
18
|
-
description: '
|
|
19
|
-
'
|
|
20
|
-
|
|
21
|
-
parameters: hideKeyboardSchema,
|
|
40
|
+
name: 'appium_mobile_keyboard',
|
|
41
|
+
description: 'Hide the software keyboard or check if it is visible (Android UiAutomator2 / iOS XCUITest). ' +
|
|
42
|
+
'action=hide uses mobile: hideKeyboard; action=is_shown uses mobile: isKeyboardShown.',
|
|
43
|
+
parameters: schema,
|
|
22
44
|
annotations: {
|
|
23
45
|
readOnlyHint: false,
|
|
24
46
|
openWorldHint: false,
|
|
25
47
|
},
|
|
26
48
|
execute: async (args, _context) => {
|
|
27
|
-
const resolved = resolveDriver(args.sessionId);
|
|
28
|
-
if (!resolved.ok) {
|
|
29
|
-
return resolved.result;
|
|
30
|
-
}
|
|
31
|
-
const { driver } = resolved;
|
|
32
49
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return errorResult(`Failed to hide keyboard. Error: ${toolErrorMessage(err)}`);
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
server.addTool({
|
|
43
|
-
name: 'appium_mobile_is_keyboard_shown',
|
|
44
|
-
description: 'Return whether the system on-screen keyboard is visible using Appium `mobile: isKeyboardShown`. ' +
|
|
45
|
-
'Supports Android (UiAutomator2) and iOS (XCUITest). Response is JSON: `{ "keyboardShown": true|false }`.',
|
|
46
|
-
parameters: z.object({
|
|
47
|
-
sessionId: z
|
|
48
|
-
.string()
|
|
49
|
-
.optional()
|
|
50
|
-
.describe('Session ID to target. If omitted, uses the active session.'),
|
|
51
|
-
}),
|
|
52
|
-
annotations: {
|
|
53
|
-
readOnlyHint: true,
|
|
54
|
-
openWorldHint: false,
|
|
55
|
-
},
|
|
56
|
-
execute: async (args, _context) => {
|
|
57
|
-
const resolved = resolveDriver(args.sessionId);
|
|
58
|
-
if (!resolved.ok) {
|
|
59
|
-
return resolved.result;
|
|
60
|
-
}
|
|
61
|
-
const { driver } = resolved;
|
|
62
|
-
try {
|
|
63
|
-
const raw = await execute(driver, 'mobile: isKeyboardShown', {});
|
|
64
|
-
if (typeof raw !== 'boolean') {
|
|
65
|
-
throw new Error(`Unexpected isKeyboardShown result type: ${typeof raw}`);
|
|
50
|
+
switch (args.action) {
|
|
51
|
+
case 'hide':
|
|
52
|
+
return await handleHide(args.sessionId, args.keys);
|
|
53
|
+
case 'is_shown':
|
|
54
|
+
return await handleIsShown(args.sessionId);
|
|
66
55
|
}
|
|
67
|
-
return textResult(JSON.stringify({ keyboardShown: raw }, null, 2));
|
|
68
56
|
}
|
|
69
57
|
catch (err) {
|
|
70
|
-
|
|
58
|
+
const msg = toolErrorMessage(err);
|
|
59
|
+
if (args.action === 'hide') {
|
|
60
|
+
return errorResult(`Failed to hide keyboard. Error: ${msg}`);
|
|
61
|
+
}
|
|
62
|
+
return errorResult(`Failed to query keyboard visibility. Error: ${msg}`);
|
|
71
63
|
}
|
|
72
64
|
},
|
|
73
65
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.js","sourceRoot":"","sources":["../../../src/tools/interactions/keyboard.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EACL,aAAa,EACb,UAAU,EACV,WAAW,EACX,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,
|
|
1
|
+
{"version":3,"file":"keyboard.js","sourceRoot":"","sources":["../../../src/tools/interactions/keyboard.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"name": "io.github.appium/appium-mcp",
|
|
4
4
|
"title": "MCP Appium - Mobile Development and Automation Server",
|
|
5
5
|
"description": "MCP server for Appium mobile automation on iOS and Android devices with test creation tools.",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.70.0",
|
|
7
7
|
"packages": [
|
|
8
8
|
{
|
|
9
9
|
"registryType": "npm",
|
|
10
10
|
"identifier": "appium-mcp",
|
|
11
|
-
"version": "1.
|
|
11
|
+
"version": "1.70.0",
|
|
12
12
|
"transport": {
|
|
13
13
|
"type": "stdio"
|
|
14
14
|
}
|
|
Binary file
|
package/src/tools/README.md
CHANGED
|
@@ -36,7 +36,7 @@ This directory contains all MCP tools available in MCP Appium.
|
|
|
36
36
|
- `drag-and-drop.ts` - Drag and drop elements or coordinates
|
|
37
37
|
- `press-key.ts` - Press navigation keys or physical buttons
|
|
38
38
|
- `set-value.ts` - Enter text
|
|
39
|
-
- `keyboard.ts` - Soft keyboard
|
|
39
|
+
- `keyboard.ts` - Soft keyboard (`appium_mobile_keyboard`; `action=hide` \| `is_shown`)
|
|
40
40
|
- `get-text.ts` - Get element text
|
|
41
41
|
- `get-page-source.ts` - Get page source (XML) from current screen
|
|
42
42
|
- `screenshot.ts` - Capture screenshots
|
|
@@ -8,91 +8,83 @@ import {
|
|
|
8
8
|
toolErrorMessage,
|
|
9
9
|
} from '../tool-response.js';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
const schema = z.object({
|
|
12
|
+
action: z
|
|
13
|
+
.enum(['hide', 'is_shown'])
|
|
14
|
+
.describe(
|
|
15
|
+
'hide: dismiss the software keyboard (mobile: hideKeyboard). ' +
|
|
16
|
+
'is_shown: whether the keyboard is visible (mobile: isKeyboardShown).'
|
|
17
|
+
),
|
|
18
|
+
keys: z
|
|
19
|
+
.array(z.string())
|
|
20
|
+
.optional()
|
|
21
|
+
.describe(
|
|
22
|
+
'hide only: optional key names to dismiss the keyboard (e.g. "done"). ' +
|
|
23
|
+
'Forwarded to mobile: hideKeyboard when non-empty. Ignored for is_shown.'
|
|
24
|
+
),
|
|
25
|
+
sessionId: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Session ID to target. If omitted, uses the active session.'),
|
|
29
|
+
});
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
name: 'appium_mobile_hide_keyboard',
|
|
28
|
-
description:
|
|
29
|
-
'Dismiss the on-screen software keyboard via Appium `mobile: hideKeyboard`. ' +
|
|
30
|
-
'Supports Android (UiAutomator2) and iOS (XCUITest). ' +
|
|
31
|
-
'May fail when no dismiss control exists; use gestures or back as a fallback.',
|
|
32
|
-
parameters: hideKeyboardSchema,
|
|
33
|
-
annotations: {
|
|
34
|
-
readOnlyHint: false,
|
|
35
|
-
openWorldHint: false,
|
|
36
|
-
},
|
|
37
|
-
execute: async (
|
|
38
|
-
args: z.infer<typeof hideKeyboardSchema>,
|
|
39
|
-
_context: Record<string, unknown> | undefined
|
|
40
|
-
): Promise<ContentResult> => {
|
|
41
|
-
const resolved = resolveDriver(args.sessionId);
|
|
42
|
-
if (!resolved.ok) {
|
|
43
|
-
return resolved.result;
|
|
44
|
-
}
|
|
45
|
-
const { driver } = resolved;
|
|
31
|
+
type KeyboardArgs = z.infer<typeof schema>;
|
|
46
32
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
33
|
+
async function handleHide(
|
|
34
|
+
sessionId: string | undefined,
|
|
35
|
+
keys: string[] | undefined
|
|
36
|
+
): Promise<ContentResult> {
|
|
37
|
+
const resolved = resolveDriver(sessionId);
|
|
38
|
+
if (!resolved.ok) {
|
|
39
|
+
return resolved.result;
|
|
40
|
+
}
|
|
41
|
+
const { driver } = resolved;
|
|
42
|
+
|
|
43
|
+
const params = keys && keys.length > 0 ? { keys } : {};
|
|
44
|
+
await execute(driver, 'mobile: hideKeyboard', params);
|
|
45
|
+
return textResult('Keyboard dismissed successfully.');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function handleIsShown(sessionId?: string): Promise<ContentResult> {
|
|
49
|
+
const resolved = resolveDriver(sessionId);
|
|
50
|
+
if (!resolved.ok) {
|
|
51
|
+
return resolved.result;
|
|
52
|
+
}
|
|
53
|
+
const { driver } = resolved;
|
|
59
54
|
|
|
55
|
+
const keyboardShown = await execute(driver, 'mobile: isKeyboardShown', {});
|
|
56
|
+
return textResult(JSON.stringify({ keyboardShown }, null, 2));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export default function keyboard(server: FastMCP): void {
|
|
60
60
|
server.addTool({
|
|
61
|
-
name: '
|
|
61
|
+
name: 'appium_mobile_keyboard',
|
|
62
62
|
description:
|
|
63
|
-
'
|
|
64
|
-
'
|
|
65
|
-
parameters:
|
|
66
|
-
sessionId: z
|
|
67
|
-
.string()
|
|
68
|
-
.optional()
|
|
69
|
-
.describe('Session ID to target. If omitted, uses the active session.'),
|
|
70
|
-
}),
|
|
63
|
+
'Hide the software keyboard or check if it is visible (Android UiAutomator2 / iOS XCUITest). ' +
|
|
64
|
+
'action=hide uses mobile: hideKeyboard; action=is_shown uses mobile: isKeyboardShown.',
|
|
65
|
+
parameters: schema,
|
|
71
66
|
annotations: {
|
|
72
|
-
readOnlyHint:
|
|
67
|
+
readOnlyHint: false,
|
|
73
68
|
openWorldHint: false,
|
|
74
69
|
},
|
|
75
70
|
execute: async (
|
|
76
|
-
args:
|
|
71
|
+
args: KeyboardArgs,
|
|
77
72
|
_context: Record<string, unknown> | undefined
|
|
78
73
|
): Promise<ContentResult> => {
|
|
79
|
-
const resolved = resolveDriver(args.sessionId);
|
|
80
|
-
if (!resolved.ok) {
|
|
81
|
-
return resolved.result;
|
|
82
|
-
}
|
|
83
|
-
const { driver } = resolved;
|
|
84
|
-
|
|
85
74
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
75
|
+
switch (args.action) {
|
|
76
|
+
case 'hide':
|
|
77
|
+
return await handleHide(args.sessionId, args.keys);
|
|
78
|
+
case 'is_shown':
|
|
79
|
+
return await handleIsShown(args.sessionId);
|
|
91
80
|
}
|
|
92
|
-
return textResult(JSON.stringify({ keyboardShown: raw }, null, 2));
|
|
93
81
|
} catch (err: unknown) {
|
|
82
|
+
const msg = toolErrorMessage(err);
|
|
83
|
+
if (args.action === 'hide') {
|
|
84
|
+
return errorResult(`Failed to hide keyboard. Error: ${msg}`);
|
|
85
|
+
}
|
|
94
86
|
return errorResult(
|
|
95
|
-
`Failed to query keyboard visibility. Error: ${
|
|
87
|
+
`Failed to query keyboard visibility. Error: ${msg}`
|
|
96
88
|
);
|
|
97
89
|
}
|
|
98
90
|
},
|