Skip to content

[MCP] uno_app_element_peer_default_action can click elements behind an open ContentDialog (modal underlay click-through) #128

@DevTKSS

Description

@DevTKSS

Current behavior

When a ContentDialog is open, Uno MCP automation (uno_app_element_peer_default_action) can still invoke the underlying page button (same elementRef as before). In our app this causes a “Pause” button to be triggered while the dialog is visible, resuming gameplay behind the dialog.

Expected behavior

When a ContentDialog is open (modal overlay), MCP automation should not be able to invoke occluded/underlay elements:

  • Either fail the action with a clear error like “element is occluded by modal dialog”, or
  • Require resolving elementRef against the topmost layer (dialog/popup root), and/or require a fresh snapshot after modal opens.

Which tool(s) are affected?

Uno MCPs

How to reproduce it (as minimally and precisely as possible)

  1. App has a button that opens a ContentDialog (see minimal snippet below).
  2. Using Uno MCP automation, click the Pause button to open the dialog.
  3. Without dismissing the dialog, run the same uno_app_element_peer_default_action again against the original Pause button elementRef.
  4. Observe: the underlying button action still fires (click-through), which can resume actions behind the dialog.

Logs
I’m including a compact repro JSON + log excerpts in the issue body:

logs.chatreplay.json

MSBuild Logs ``` 2025-12-22T12:19:36.6391124+01:00 | GamePlayPage loaded 2025-12-22T12:19:36.6410560+01:00 | Auto-started. IsRunning=True IsPaused=False 2025-12-22T12:19:45.6623839+01:00 | TogglePause[1] begin. IsRunning=True IsPaused=False 2025-12-22T12:19:45.6627747+01:00 | TogglePause[1] after pause. IsRunning=True IsPaused=True 2025-12-22T12:19:45.6628991+01:00 | TogglePause[1] showing dialog... 2025-12-22T12:19:45.6633703+01:00 | Creating pause ContentDialog instance 2025-12-22T12:19:45.6724663+01:00 | Difficulty changed: Easy 2025-12-22T12:19:45.6729503+01:00 | Showing pause dialog. SettingsVisible=Collapsed 2025-12-22T12:19:52.2245061+01:00 | TogglePause[2] begin. IsRunning=True IsPaused=True 2025-12-22T12:19:52.2250356+01:00 | TogglePause[2] resume fast-path (no dialog). 2025-12-22T12:19:52.2253501+01:00 | TogglePause[2] after resume fast-path. IsRunning=True IsPaused=False 2025-12-22T12:24:54.0219550+01:00 | GamePlayPage loaded 2025-12-22T12:24:54.0223442+01:00 | Auto-started. IsRunning=True IsPaused=False 2025-12-22T12:28:44.3240065+01:00 | GamePlayPage loaded 2025-12-22T12:28:44.3259903+01:00 | Auto-started. IsRunning=True IsPaused=False 2025-12-22T12:28:57.9334247+01:00 | TogglePause[1] begin. IsRunning=True IsPaused=False 2025-12-22T12:28:57.9338375+01:00 | TogglePause[1] after pause. IsRunning=True IsPaused=True 2025-12-22T12:28:57.9339709+01:00 | TogglePause[1] showing dialog... 2025-12-22T12:28:57.9344546+01:00 | Creating pause ContentDialog instance 2025-12-22T12:28:57.9438020+01:00 | Difficulty changed: Easy 2025-12-22T12:28:57.9443159+01:00 | Showing pause dialog. SettingsVisible=Collapsed 2025-12-22T12:29:05.8932452+01:00 | TogglePause[2] begin. IsRunning=True IsPaused=True 2025-12-22T12:29:05.8938506+01:00 | TogglePause[2] ignored: pause dialog is open. 2025-12-22T12:29:19.1131956+01:00 | TogglePause[1] dialog completed: Primary 2025-12-22T12:29:19.1133741+01:00 | TogglePause[1] resuming after dialog. 2025-12-22T12:29:19.1136107+01:00 | TogglePause[1] end. IsRunning=True IsPaused=False ```

Log excerpt showing the bug (resume while dialog open):

  • TogglePause[2] begin. IsRunning=True IsPaused=True
  • TogglePause[2] resume fast-path (no dialog).
  • TogglePause[2] after resume fast-path. IsRunning=True IsPaused=False

Minimal repro code
XAML:

<Grid>
  <Button x:Name="PauseButton"
          Content="Pause"
          Click="OnPauseClick" />
</Grid>

Code-behind:

private ContentDialog? _dialog;
private bool _paused;

private async void OnPauseClick(object sender, RoutedEventArgs e)
{
    _paused = true;

    _dialog ??= new ContentDialog
    {
        XamlRoot = XamlRoot,
        Title = "Paused",
        PrimaryButtonText = "Resume",
        Content = "Game paused."
    };

    await _dialog.ShowAsync();

    _paused = false;
}

Workaround

App-side guard to ignore underlay clicks while the dialog is open (not ideal; the automation should respect modal overlays).

Renderer

  • Skia
  • Native

Affected platforms

Desktop - net9.0-desktop (on Windows)

Uno.Sdk version

  • 6.4.42 (from global.json)

IDE used

Visual Studio Code on Windows

IDE version

1.107.1

Uno Platform Extension version

0.23.6

Relevant plugins

No response

Anything else we need to know?

This appears to be an automation hit-testing / occlusion issue in MCP: a stale elementRef remains invokable even when a modal ContentDialog is on top.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions