loading…
Search for a command to run...
loading…
An MCP server for headless Qt/PySide6 GUI testing that enables AI assistants to launch desktop applications via Xvfb and perform visual verification. It support
An MCP server for headless Qt/PySide6 GUI testing that enables AI assistants to launch desktop applications via Xvfb and perform visual verification. It supports widget discovery, screenshot capture, and simulated user interactions like clicks, typing, and keyboard shortcuts.
An MCP server for headless Qt/PySide6 GUI testing. Enables AI assistants like Claude to visually test and interact with Qt desktop applications.
Repository: github.com/neatobandit0/qt-pilot
git clone https://github.com/neatobandit0/qt-pilot.git ~/.claude/plugins/qt-pilot
pip install -r ~/.claude/plugins/qt-pilot/requirements.txt
Copy the plugin to your Claude plugins directory:
cp -r qt-pilot ~/.claude/plugins/
Then add to your ~/.claude.json:
{
"mcpServers": {
"qt-pilot": {
"type": "stdio",
"command": "python3",
"args": ["/path/to/qt-pilot/server/main.py"]
}
}
}
pip install mcp PySide6
Also requires Xvfb for headless display:
# Debian/Ubuntu
sudo apt install xvfb
# RHEL/CentOS/Fedora
sudo yum install xorg-x11-server-Xvfb
# macOS (via Homebrew)
brew install xquartz
launch_appLaunch a Qt application headlessly.
# Script mode
launch_app(script_path="/path/to/test_gui.py")
# Module mode
launch_app(module="myapp.main", working_dir="/path/to/project")
capture_screenshotCapture the current window.
capture_screenshot(output_path="/tmp/screenshot.png")
click_widgetClick a widget by its object name.
click_widget(widget_name="submit_button", button="left")
hover_widgetHover over a widget.
hover_widget(widget_name="menu_item")
type_textType text into a widget or focused widget.
type_text(text="hello world", widget_name="search_input")
type_text(text="hello") # Types into currently focused widget
press_keySimulate a key press with optional modifiers.
press_key(key="Enter")
press_key(key="S", modifiers=["Ctrl"]) # Ctrl+S
press_key(key="Tab")
find_widgetsList widgets matching a name pattern.
find_widgets(name_pattern="*") # All named widgets
find_widgets(name_pattern="btn_*") # Widgets starting with "btn_"
get_widget_infoGet detailed widget information.
get_widget_info(widget_name="submit_button")
# Returns: type, visible, enabled, size, position, text, checked state, etc.
get_app_statusCheck if the application is still running and get diagnostics.
get_app_status()
# Returns: {"running": true, "exit_code": null, "stderr": "", "display": ":99"}
wait_for_idleWait for the Qt event queue to settle after actions.
click_widget(widget_name="load_button")
wait_for_idle(timeout=5.0) # Wait for async operations to complete
capture_screenshot()
close_appClose the running application.
close_app()
For widget interactions to work, your Qt application must:
Set object names on interactive widgets:
button = QPushButton("Click Me")
button.setObjectName("my_button") # Required for widget discovery
Use QApplication (not QCoreApplication)
Show at least one window
┌─────────────────────────────┐
│ AI Assistant (Claude) │
└─────────────┬───────────────┘
│ MCP Protocol (stdio)
▼
┌─────────────────────────────┐
│ MCP Server (main.py) │
│ - Tool definitions │
│ - Process management │
└─────────────┬───────────────┘
│ Unix Socket (IPC)
▼
┌─────────────────────────────┐
│ Test Harness (harness.py) │
│ - Runs inside Xvfb │
│ - QTest interactions │
│ - Widget introspection │
├─────────────────────────────┤
│ Your Qt Application │
└─────────────────────────────┘
# 1. Launch a test app
launch_app(module="myapp.main", working_dir="/path/to/project")
# 2. List available widgets
find_widgets()
# 3. Interact with the UI
click_widget(widget_name="login_button")
wait_for_idle()
# 4. Type into a field
type_text(text="[email protected]", widget_name="email_input")
press_key(key="Tab")
type_text(text="password123", widget_name="password_input")
# 5. Submit and capture result
click_widget(widget_name="submit_button")
wait_for_idle(timeout=3.0)
capture_screenshot(output_path="/tmp/result.png")
# 6. Clean up
close_app()
setObjectName() calledfind_widgets() to list available widget nameslaunch_app() firstget_app_status() to check for errorsstderr field contains crash informationwait_for_idle() after launch for window to renderMIT License - see LICENSE file.
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"qt-pilot": {
"command": "npx",
"args": []
}
}
}