Skip to content

fix(patrol_mcp): pass device serial to screenshot command (fails with multiple devices attached)#3131

Merged
zoskar merged 2 commits into
leancodepl:masterfrom
godzeit:fix/patrol-mcp-screenshot-device-serial
Jul 6, 2026
Merged

fix(patrol_mcp): pass device serial to screenshot command (fails with multiple devices attached)#3131
zoskar merged 2 commits into
leancodepl:masterfrom
godzeit:fix/patrol-mcp-screenshot-device-serial

Conversation

@godzeit

@godzeit godzeit commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Problem

The screenshot MCP tool shells out to capture the device screen without ever targeting a specific device:

  • Android: adb exec-out screencap -p (no -s <serial>).
  • iOS: xcrun simctl io booted screenshot ... (booted instead of the actual UDID).

ScreenshotService.handleScreenshotRequest(Device? device) already receives the patrol_cli Device for the active session, but only uses it to pick the platform (ScreenshotPlatform.fromDevice) — the device identity itself is discarded before the command is built.

Repro (Android, 2+ devices/emulators attached — common when running parallel emulators)

$ adb exec-out screencap -p
error: more than one device/emulator

With -s <serial> both devices return a valid PNG; without it the tool call fails outright. On iOS the failure mode is worse — with 2+ booted simulators, booted picks whichever simctl considers "the" booted device, which may silently be the wrong one instead of erroring.

Verified live against patrol_mcp 0.1.4 while running Patrol against a production Flutter monorepo with parallel Android emulators.

Fix

  • ScreenshotPlatform now exposes argsFor(Device device) instead of a static args list, and builds the command with the device's identity:
    • Android: adb -s <device.id> exec-out screencap -p
    • iOS: xcrun simctl io <device.id> screenshot --type=png /dev/stdout (Device.id is the simulator UDID on iOS, per ios_test_backend.dart, which already does simctl ... device.id instead of booted)
  • _captureScreenshot now takes the Device and threads it through to argsFor.

This aligns with how patrol_cli itself already targets devices — e.g. android_test_backend.dart sets 'ANDROID_SERIAL': device.id when running tests, and ios_test_backend.dart passes device.id (not booted) to simctl. The MCP screenshot tool was the odd one out.

Related gap fixed in the same package: native-tree

While auditing patrol_mcp for the same class of bug, NativeTreeService._setupConnection calls Adb().forwardPorts(fromHost: port, toDevice: port) without a device argument. The adb package's forwardPorts already accepts an optional device serial (see packages/adb/lib/src/adb.dart) specifically to disambiguate when more than one device is attached. Passed device: device.id here too, since it's the same root cause and a one-line fix in a file already touched by this class of bug.

Changes

  • packages/patrol_mcp/lib/src/screenshot_service.dart — pass device serial/UDID to adb/simctl.
  • packages/patrol_mcp/lib/src/native_tree_service.dart — pass device serial to Adb().forwardPorts.
  • packages/patrol_mcp/CHANGELOG.md — unreleased entry.

Verification

dart analyze lib/src/screenshot_service.dart lib/src/native_tree_service.dart
# No issues found!

No test/ directory exists yet for patrol_mcp, so no existing test coverage was touched; happy to add coverage if maintainers point me at the preferred pattern for exercising Process.start args in this package.


🤖 Generated with Claude Code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@zoskar

zoskar commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

@godzeit Thanks for the contribution!

@zoskar zoskar left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed multi device support in general to TODO, thanks for contribution 💪

@zoskar zoskar merged commit 8bfdd42 into leancodepl:master Jul 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants