appium-mcp 1.71.6 → 1.72.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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [1.72.0](https://github.com/appium/appium-mcp/compare/v1.71.6...v1.72.0) (2026-05-01)
2
+
3
+ ### Features
4
+
5
+ * add APPIUM_MCP_ON_CLIENT_DISCONNECT toggle ([#306](https://github.com/appium/appium-mcp/issues/306)) ([b77cae4](https://github.com/appium/appium-mcp/commit/b77cae4fe6753599f4c04cfedbb6e1b362c23ed2))
6
+
1
7
  ## [1.71.6](https://github.com/appium/appium-mcp/compare/v1.71.5...v1.71.6) (2026-05-01)
2
8
 
3
9
  ### Bug Fixes
package/README.md CHANGED
@@ -143,6 +143,7 @@ This will automatically configure the MCP server for use with Claude Code. Make
143
143
  | `CAPABILITIES_CONFIG` | Optional | Absolute path to a `capabilities.json` file with per-platform capability presets |
144
144
  | `SCREENSHOTS_DIR` | Optional | Directory where screenshots and screen recordings are saved. Defaults to the current working directory |
145
145
  | `NO_UI` | Optional | Set to `true` or `1` to disable HTML UI components — faster responses, fewer tokens. See [NO_UI Mode](#no_ui-mode) |
146
+ | `APPIUM_MCP_ON_CLIENT_DISCONNECT` | Optional | Session cleanup when the MCP client disconnects: `delete_all` (default) deletes **MCP-owned** Appium sessions (`safeDeleteAllSessions`); `skip` keeps those sessions across disconnects (e.g. HTTP/stream clients that reconnect). Attached/remote sessions are not removed by this path. See [MCP disconnect behavior](#mcp-disconnect-behavior). |
146
147
  | `APPIUM_MCP_WDA_APP_PATH` | Optional | Absolute path to a pre-extracted `WebDriverAgentRunner-Runner.app` bundle. When set, `prepare_ios_simulator` skips all GitHub downloads and uses this bundle directly — useful in environments where external downloads are blocked |
147
148
  | `REMOTE_SERVER_URL_ALLOW_REGEX` | Optional | Regex pattern that remote Appium server URLs must match. Defaults to `^https?://` |
148
149
  | `AI_VISION_API_BASE_URL` | Required for AI Vision | Base URL of the OpenAI-compatible vision model API |
@@ -321,6 +322,14 @@ The following tools return lightweight text-only responses when NO_UI is enabled
321
322
  - ✅ Scripted automation where human interaction is not needed
322
323
  - ❌ Interactive debugging and exploration (keep UI enabled for better experience)
323
324
 
325
+ #### MCP disconnect behavior
326
+
327
+ By default (`APPIUM_MCP_ON_CLIENT_DISCONNECT` unset or `delete_all`), when the **MCP client disconnects**, this server **deletes every MCP-owned Appium session** (the same sessions `safeDeleteAllSessions` targets) so embedded drivers are not left running after a short-lived assistant run. **Attached** sessions (`ownership=attached`) are unchanged by this teardown.
328
+
329
+ HTTP and streamable MCP clients may **disconnect briefly** (reconnect, reload, proxy). If that tears down drivers you still need, set `APPIUM_MCP_ON_CLIENT_DISCONNECT` to `skip` in your MCP server `env` (same pattern as `NO_UI` above). With `skip`, sessions **survive** disconnect until you call `appium_session_management` with `action=delete`, or you stop the Appium server / process.
330
+
331
+ **Tradeoff:** `skip` can leave **orphaned sessions** on your Appium server if nothing cleans up — use it when disconnect is not the same as “automation finished.”
332
+
324
333
  ## 🎯 Available Tools
325
334
 
326
335
  MCP Appium provides a comprehensive set of tools organized into the following categories:
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAMlC,QAAA,MAAM,MAAM,+CAKV,CAAC;AAgCH,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AA0BlC,QAAA,MAAM,MAAM,+CAKV,CAAC;AA2CH,eAAe,MAAM,CAAC"}
package/dist/server.js CHANGED
@@ -3,6 +3,21 @@ import registerTools from './tools/index.js';
3
3
  import registerResources from './resources/index.js';
4
4
  import { listSessions, safeDeleteAllSessions } from './session-store.js';
5
5
  import log from './logger.js';
6
+ /**
7
+ * MCP disconnect policy for Appium sessions tracked by this server.
8
+ * - delete_all (default): end every owned session when the MCP client disconnects (avoids leaked drivers).
9
+ * - skip: keep sessions across disconnects — needed for flaky HTTP/stream clients that reconnect briefly.
10
+ */
11
+ function disconnectSessionPolicyFromEnv() {
12
+ const raw = process.env.APPIUM_MCP_ON_CLIENT_DISCONNECT?.trim().toLowerCase();
13
+ if (raw === 'skip') {
14
+ return 'skip';
15
+ }
16
+ if (raw !== 'delete_all') {
17
+ log.warn(`APPIUM_MCP_ON_CLIENT_DISCONNECT="${raw}" is not recognized (expected delete_all or skip); defaulting to delete_all`);
18
+ }
19
+ return 'delete_all';
20
+ }
6
21
  const server = new FastMCP({
7
22
  name: 'MCP Appium',
8
23
  version: '1.0.0',
@@ -16,7 +31,13 @@ server.on('connect', (event) => {
16
31
  });
17
32
  server.on('disconnect', async (event) => {
18
33
  log.info('Client disconnected:', event.session);
34
+ const policy = disconnectSessionPolicyFromEnv();
19
35
  const ownedSessions = listSessions().filter((session) => session.ownership === 'owned');
36
+ if (ownedSessions.length > 0 && policy === 'skip') {
37
+ log.info(`${ownedSessions.length} owned session(s) retained after MCP disconnect ` +
38
+ '(APPIUM_MCP_ON_CLIENT_DISCONNECT=skip). Delete explicitly via appium_session_management (action=delete) when finished.');
39
+ return;
40
+ }
20
41
  if (ownedSessions.length > 0) {
21
42
  try {
22
43
  log.info(`${ownedSessions.length} owned session(s) detected on disconnect, cleaning up...`);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,iBAAiB,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,GAAG,MAAM,aAAa,CAAC;AAE9B,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;IACzB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,OAAO;IAChB,YAAY,EACV,mPAAmP;CACtP,CAAC,CAAC;AAEH,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtB,oDAAoD;AACpD,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;IAC7B,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IACtC,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,YAAY,EAAE,CAAC,MAAM,CACzC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,OAAO,CAC3C,CAAC;IACF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CACN,GAAG,aAAa,CAAC,MAAM,0DAA0D,CAClF,CAAC;YACF,MAAM,YAAY,GAAG,MAAM,qBAAqB,EAAE,CAAC;YACnD,GAAG,CAAC,IAAI,CACN,GAAG,YAAY,oDAAoD,CACpE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAC7C,OAAO,iBAAiB,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACzE,OAAO,GAAG,MAAM,aAAa,CAAC;AAI9B;;;;GAIG;AACH,SAAS,8BAA8B;IACrC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9E,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;QACzB,GAAG,CAAC,IAAI,CACN,oCAAoC,GAAG,6EAA6E,CACrH,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,OAAO,CAAC;IACzB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,OAAO;IAChB,YAAY,EACV,mPAAmP;CACtP,CAAC,CAAC;AAEH,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtB,oDAAoD;AACpD,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE;IAC7B,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IACtC,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,8BAA8B,EAAE,CAAC;IAEhD,MAAM,aAAa,GAAG,YAAY,EAAE,CAAC,MAAM,CACzC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,OAAO,CAC3C,CAAC;IAEF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QAClD,GAAG,CAAC,IAAI,CACN,GAAG,aAAa,CAAC,MAAM,kDAAkD;YACvE,wHAAwH,CAC3H,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,CACN,GAAG,aAAa,CAAC,MAAM,0DAA0D,CAClF,CAAC;YACF,MAAM,YAAY,GAAG,MAAM,qBAAqB,EAAE,CAAC;YACnD,GAAG,CAAC,IAAI,CACN,GAAG,YAAY,oDAAoD,CACpE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appium-mcp",
3
3
  "mcpName": "io.github.appium/appium-mcp",
4
- "version": "1.71.6",
4
+ "version": "1.72.0",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
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.71.6",
6
+ "version": "1.72.0",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "identifier": "appium-mcp",
11
- "version": "1.71.6",
11
+ "version": "1.72.0",
12
12
  "transport": {
13
13
  "type": "stdio"
14
14
  }
Binary file
package/src/server.ts CHANGED
@@ -4,6 +4,26 @@ import registerResources from './resources/index.js';
4
4
  import { listSessions, safeDeleteAllSessions } from './session-store.js';
5
5
  import log from './logger.js';
6
6
 
7
+ type DisconnectSessionPolicy = 'delete_all' | 'skip';
8
+
9
+ /**
10
+ * MCP disconnect policy for Appium sessions tracked by this server.
11
+ * - delete_all (default): end every owned session when the MCP client disconnects (avoids leaked drivers).
12
+ * - skip: keep sessions across disconnects — needed for flaky HTTP/stream clients that reconnect briefly.
13
+ */
14
+ function disconnectSessionPolicyFromEnv(): DisconnectSessionPolicy {
15
+ const raw = process.env.APPIUM_MCP_ON_CLIENT_DISCONNECT?.trim().toLowerCase();
16
+ if (raw === 'skip') {
17
+ return 'skip';
18
+ }
19
+ if (raw !== 'delete_all') {
20
+ log.warn(
21
+ `APPIUM_MCP_ON_CLIENT_DISCONNECT="${raw}" is not recognized (expected delete_all or skip); defaulting to delete_all`
22
+ );
23
+ }
24
+ return 'delete_all';
25
+ }
26
+
7
27
  const server = new FastMCP({
8
28
  name: 'MCP Appium',
9
29
  version: '1.0.0',
@@ -21,9 +41,20 @@ server.on('connect', (event) => {
21
41
 
22
42
  server.on('disconnect', async (event) => {
23
43
  log.info('Client disconnected:', event.session);
44
+ const policy = disconnectSessionPolicyFromEnv();
45
+
24
46
  const ownedSessions = listSessions().filter(
25
47
  (session) => session.ownership === 'owned'
26
48
  );
49
+
50
+ if (ownedSessions.length > 0 && policy === 'skip') {
51
+ log.info(
52
+ `${ownedSessions.length} owned session(s) retained after MCP disconnect ` +
53
+ '(APPIUM_MCP_ON_CLIENT_DISCONNECT=skip). Delete explicitly via appium_session_management (action=delete) when finished.'
54
+ );
55
+ return;
56
+ }
57
+
27
58
  if (ownedSessions.length > 0) {
28
59
  try {
29
60
  log.info(