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
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
xcrun simctl create A "iPhone 17"andxcrun simctl create B "iPhone 17", boot both.control { action: "attach", udid: A }→ reports panel opened for A.control { action: "attach", udid: B }→ reports panel opened for B.control { action: "screenshot" }(noudid) → returns A, not B. Same fortap.xcrun simctl shutdown B, thencontrol { action: "attach", udid: B }→ reports "already attached", B staysShutdown,screenshotfails withNo Image available to encode.xcrun simctl delete B, thencontrol { action: "attach" }→ still reports "already attached" to the deleted B;attachwith a valid booted UDID does not clear it; onlydetach+attachdoes.
Expected
attach {udid: X}should make X the target for subsequentudid-less actions, or fail loudly. It should never report success for a device it is not going to route actions to.attachon aShutdowndevice 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 requiringdetachfirst. screenshot'sNo Image available to encodeshould 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-simcrash 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.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗