Skip to main content
Glama

semantic-gui-agent-testing

Semantic GUI automation for LLM agents. Drive real Android and Windows UIs through a single platform-neutral API — no hard-coded coordinates, no model calls for element localization.

Elements are located by meaning (text, content-desc, resource-id/AutomationId, natural-language description) against the accessibility tree dumped from the device, with an injectable OCR provider as a last-resort visual fallback.

Why

LLM-driven GUI agents usually fail on three things: brittle coordinate scripts, expensive screenshot-per-step vision loops, and flaky waits. This framework addresses all three:

Problem

Approach

Brittle coordinates

Semantic matching over the accessibility tree, deterministic and re-runnable

Vision-loop cost

Localization is pure Python — zero model calls; OCR is only a fallback

Flaky waits

Polling state waits, declarative assertions, per-step error-isolated batches

Related MCP server: waydroid-mcp

Components

  • Executors — AndroidExecutor (adb + uiautomator2) and WindowsExecutor (UI Automation via pywinauto) behind one abstract GUIExecutor.

  • Semantic matcher — deterministic scoring across text / content-desc / resource-id / description surfaces, with ambiguity flagging.

  • Incremental UI updates — Merkle-hash caching so unchanged screens are detected without re-processing.

  • Visual fallback — pluggable OCR provider, used only when the tree fails.

  • MCP server — expose the executors to any MCP-capable agent over stdio (newline-delimited JSON-RPC 2.0, no SDK dependency).

  • Batch + waits + assertions — execution optimizations for agent loops.

  • Sessions — per-agent isolation of executor instances and caches.

Install

Python 3.10+.

pip install -e .            # core (no device deps)
pip install -e ".[android]" # + uiautomator2
pip install -e ".[windows]" # + pywinauto (Windows only)
pip install -e ".[dev]"     # + pytest

Quickstart (no device needed)

from sgat.models import SemanticTarget
from sgat.registry import default_registry

with default_registry().create("stub") as executor:
    result = executor.tap(SemanticTarget(id="ok", text="OK"))
    print(result.success, result.detail)  # True: matched via text

Smoke-test the MCP server against the in-memory stub:

python -m sgat.mcp.server --executor stub

MCP tools

Tool

Purpose

find_element

Locate an element semantically, return best match + candidates

tap

Locate and tap the element center

input_text

Type text, optionally into a located element

press_back

Platform back navigation

wait_for

Poll until an element appears

assert_element

Assert existence / text / enabled / clickable

Point an MCP client at a real device:

python -m sgat.mcp.server --executor android --serial <serial>
python -m sgat.mcp.server --executor windows --window-title "Notepad"

Status

  • Unit tested: 16 tests, CI on Ubuntu + Windows, Python 3.10/3.12.

  • Real-device benchmarks: not yet measured. benchmarks/run_benchmarks.py is the harness; run it against your devices and record results in docs/benchmarks.md. No numbers are published here until they come from real runs.

Documentation

License

MIT

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables agents to interact with Android via text-based UI trees instead of screenshots, supporting taps, swipes, input, macro recording, and device control through an MCP server and CLI.
    1
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables MCP-compatible AI platforms to see the screen and operate any desktop software through real mouse clicks, text input, key presses, and scripted scenario execution.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to access and act on web, desktop, and mobile interfaces via semantic accessibility trees, using MCP tools for querying, navigating, and executing deterministic UI actions without relying on screenshots or pixel coordinates.
    11 npm
    Apache 2.0