iOS Simulator MCP/panel: attach reports a device it does not route actions to — taps land on the wrong simulator, and shut-down or deleted devices are reported as attached

Status Open
Maintainer reply None cached
Activity 1 comment · opened Aug 20, 2026

Description

This report covers three likely related device-state and targeting defects in the Desktop app.s iOS Simulator panel / mcp__Claude_Code_iOS_Simulator__control. The observed common symptom is that the device attach reports is not always the device that subsequent udid-less actions resolve to. Separately, attach neither validates the target.s boot state nor reliably replaces or clears a previous target.

The practical consequence is that an agent can be told "the panel is on device X", then send taps and swipes to device Y without any error — including a simulator currently being used by a different Claude Desktop session, since simulator state is machine-global. The tool does not expose per-session device ownership, so this is an observed cross-session risk rather than a claim about an internal ownership model.

All three were reproduced from a clean state on throwaway devices created with simctl create, verbatim tool output below.

---

1. attach {udid: X} claims success but does not become the default target
> control { action: "attach", udid: "4D388256-…" }        # ReproB, booted
< Simulator panel opened for ReproB (4D388256-190C-41FD-8156-004EEE2A69AE).
  Coordinate space for tap/swipe: 402x874 points (origin top-left).

> control { action: "screenshot" }                         # no udid
< Screenshot of iPhone 17 Pro (5800AF4B-90D7-4F28-A8EC-80C8E2AE4B75).   # ← different device

Passing udid on the action itself resolves correctly, which isolates this to default-device resolution rather than the capture path:

> control { action: "screenshot", udid: "149E7DAB-…" }
< Screenshot of 149E7DAB-BA80-462E-9D0E-E5E8840997D4.       # ← correct

Input actions follow the same wrong route. Immediately after attach reported ReproC:

> control { action: "tap", x: 157, y: 843 }
< Tapped at (157, 843) on iPhone 17 Pro (5800AF4B-90D7-4F28-A8EC-80C8E2AE4B75).

attach appears to append to a set rather than switch, which detach confirms — one call tears down every device attached so far, including ones the session never asked for:

> control { action: "detach" }
< Detached iPhone 17 Pro (5800AF4B-…), ReproB (4D388256-…), ReproC (59CA0F86-…).

With exactly one device in that set the resolution is correct; with more than one it drifts to another member. So the bug only shows up once a session has attached twice — which is the normal flow when switching devices.

2. attach on an existing-but-shut-down device reports success and does not boot it
$ xcrun simctl shutdown 149E7DAB-…      # device is Shutdown, verified via simctl

> control { action: "attach", udid: "149E7DAB-…" }
< Simulator panel already attached to ClaudeReproDevice (149E7DAB-…).
  Coordinate space for tap/swipe: 402x874 points (origin top-left).

$ xcrun simctl list devices | grep 149E7DAB
    ClaudeReproDevice (149E7DAB-…) (Shutdown)        # ← attach did not boot it

> control { action: "screenshot" }
< screenshot failed: Error Domain=com.facebook.FBSimulatorControl Code=0
  "No Image available to encode"

The success message carries a coordinate space, so it reads as a fully working attach. Another device (iPhone 17 Pro) was booted the whole time and was never offered as a fallback.

This also contradicts the panel's own onboarding copy, which states verbatim that "shut-down devices are booted automatically" (ko: 종료된 기기는 자동으로 부팅됩니다). In the reproduced MCP attach path, this automatic boot does not occur.

Note that a genuinely nonexistent UDID is rejected properly, so the existence check runs and the boot-state check simply doesn't:

> control { action: "attach", udid: "00000000-DEAD-BEEF-0000-000000000000" }
< Could not attach simulator panel: Failed to read the device's state:
  No simulator with UDID 00000000-DEAD-BEEF-0000-000000000000
3. A deleted device stays pinned for the lifetime of the panel, and an explicit re-attach does not clear it
$ xcrun simctl delete 149E7DAB-…        # another device remains booted

> control { action: "attach" }
< Simulator panel already attached to ClaudeReproDevice (149E7DAB-…)    # ← device no longer exists

> control { action: "screenshot" }
< screenshot failed: No simulator with UDID 149E7DAB-BA80-462E-9D0E-E5E8840997D4

> control { action: "attach", udid: "5800AF4B-…" }                      # valid, booted
< Simulator panel opened for iPhone 17 Pro (5800AF4B-…)                 # reports success

> control { action: "screenshot" }
< screenshot failed: No simulator with UDID 149E7DAB-BA80-462E-9D0E-E5E8840997D4   # ← still pinned

Only detach followed by attach recovers:

> control { action: "detach" }
> control { action: "attach", udid: "5800AF4B-…" }
> control { action: "screenshot" }
< Screenshot of iPhone 17 Pro (5800AF4B-…)         # ← recovered

The same failure is visible in the panel UI, not just over MCP. During this investigation a second Desktop session's panel silently latched onto one of the throwaway devices as soon as it booted — the session never asked for it — and when that device was deleted the panel froze on:

기기 상태를 읽지 못했습니다: UDID 59CA0F86-898D-4FEF-A820-86DB9F0800EC에 해당하는 시뮬레이터가 없습니다.
(Failed to read the device's state: no simulator matching UDID 59CA0F86-…)

with only a "Connect simulator" button, which re-runs the same doomed attach. Meanwhile the adjacent panel in the same window was streaming a healthy iPhone 17 Pro at 60 FPS. Two panels, same machine, same moment: one fine, one stuck on a deleted UDID the user has no way to recognise.

Worse, that dead panel is orphaned from the backend. After a later detach, the tool reports only the live device:

> control { action: "detach" }
< Detached iPhone 17 Pro (5800AF4B-…)          # the dead panel is not listed

yet the dead panel is still on screen, still pinned to 59CA0F86-…, and its "Connect simulator" button still retries that UDID. The backend has forgotten it, so no MCP call — detach, attach, or otherwise — can clear it. The only remaining action is closing the panel by hand with the X.

This is how a panel instance gets stuck: an attached device can disappear through simctl delete, a runtime reinstall, or another session cleaning up. After that, the panel remains unusable for the lifetime of that panel instance, with an error that names a UDID the user cannot map to anything, while the documented escape hatch — attaching by UDID — silently fails to help.

Repro steps

  1. xcrun simctl create A "iPhone 17" and xcrun simctl create B "iPhone 17", boot both.
  2. control { action: "attach", udid: A } → reports panel opened for A.
  3. control { action: "attach", udid: B } → reports panel opened for B.
  4. control { action: "screenshot" } (no udid) → returns A, not B. Same for tap.
  5. xcrun simctl shutdown B, then control { action: "attach", udid: B } → reports "already attached", B stays Shutdown, screenshot fails with No Image available to encode.
  6. xcrun simctl delete B, then control { action: "attach" } → still reports "already attached" to the deleted B; attach with a valid booted UDID does not clear it; only detach + attach does.

Expected

  • attach {udid: X} should make X the target for subsequent udid-less actions, or fail loudly. It should never report success for a device it is not going to route actions to.
  • attach on a Shutdown device should either boot it or return an error naming the boot state, not "already attached" with a coordinate space.
  • A panel should not auto-adopt a device the session never asked for, since that is what silently hands a session a device that some other workflow is about to delete.
  • When the attached device disappears, the panel should drop the stale UDID and either fall back to a booted device or return an actionable error (e.g. list the available devices). At minimum, an explicit attach {udid: <valid>} must clear the dead pin without requiring detach first.
  • screenshot's No Image available to encode should be replaced by a message that names the cause (device is shut down / device no longer exists), since today the same opaque string appears for unrelated failures — see #81864.

Environment

  • Claude Desktop 1.32885.1
  • macOS 27.0 beta (26A5416b), MacBook Air M4 (Mac16,12)
  • Xcode 26.6 (17F113), xcode-select/Applications/Xcode.app/Contents/Developer
  • iOS 26.5 (23F77) simulator runtime
  • No claude-ios-sim crash reports during any of this — the helper stayed alive throughout, so this is unrelated to the Metal crash-loop family (#80177 / #80472 / #83011).

Related

  • #81864 — panel does not recover after host reboot, also surfaces No Image available to encode. Same "panel does not renegotiate state" family, different trigger (host reboot vs. device shutdown/deletion) and, unlike that report, here the underlying capture path is provably healthy for other devices at the same moment.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗