Qt Pilot MCP Server

An MCP server for headless Qt/PySide6 GUI testing.

★ 8neatobandit0/qt-pilot ↗by neatobandit0updated
Manual setup required. The maintainer's config contains paths only you know - edit the placeholders below before adding it to Claude Code.
1

Prepare the server locally

Run this once before adding it to Claude Code.

git clone https://github.com/neatobandit0/qt-pilot.git ~/.claude/plugins/qt-pilot
pip install -r ~/.claude/plugins/qt-pilot/requirements.txt
2

Register it in Claude Code

claude mcp add qt-pilot -- python3 /path/to/qt-pilot/server/main.py

Replace any placeholder paths in the command with the real path on your machine.

3

Make your agent remember this setup

qt-pilot's config, env vars, and the gotchas you hit — recalled in every future Claude Code, Cursor, and Codex session.

npx conare@latest

Free · one command · indexes the sessions already on disk. Set up in the browser instead →

What it does

  • Launch Qt applications headlessly via Xvfb
  • Capture screenshots for visual verification
  • Simulate user interactions like clicks, hovers, and keyboard input
  • Discover and introspect widgets by object name
  • Monitor application health and capture stderr

Tools 11

launch_appLaunch a Qt application headlessly.
capture_screenshotCapture the current window.
click_widgetClick a widget by its object name.
hover_widgetHover over a widget.
type_textType text into a widget or focused widget.
press_keySimulate a key press with optional modifiers.
find_widgetsList widgets matching a name pattern.
get_widget_infoGet detailed widget information.
get_app_statusCheck if the application is still running and get diagnostics.
wait_for_idleWait for the Qt event queue to settle after actions.
close_appClose the running application.

Try it

Launch the application at /path/to/myapp.py and list all available widgets.
Click the 'login_button', wait for the UI to settle, and capture a screenshot.
Type 'admin' into the 'username_input' field and press the Tab key.
Check the current status of the running Qt application and verify if it is still responsive.
Find all widgets starting with 'btn_' and get detailed information for the 'submit_button'.
Original README from neatobandit0/qt-pilot

Qt Pilot

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

Features

  • Launch Qt apps headlessly via Xvfb virtual display
  • Capture screenshots for visual verification
  • Simulate interactions: clicks, hovers, keyboard input
  • Widget discovery by object name
  • App health monitoring with stderr capture
  • Full Qt introspection via QTest and Qt APIs

Installation

From GitHub

git clone https://github.com/neatobandit0/qt-pilot.git ~/.claude/plugins/qt-pilot
pip install -r ~/.claude/plugins/qt-pilot/requirements.txt

Manual Installation

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"]
    }
  }
}

Dependencies

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

MCP Tools

`launch_app`

Launch 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_screenshot`

Capture the current window.

capture_screenshot(output_path="/tmp/screenshot.png")

`click_widget`

Click a widget by its object name.

click_widget(widget_name="submit_button", button="left")

`hover_widget`

Hover over a widget.

hover_widget(widget_name="menu_item")

`type_text`

Type 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_key`

Simulate a key press with optional modifiers.

press_key(key="Enter")
press_key(key="S", modifiers=["Ctrl"])  # Ctrl+S
press_key(key="Tab")

`find_widgets`

List widgets matching a name pattern.

find_widgets(name_pattern="*")  # All named widgets
find_widgets(name_pattern="btn_*")  # Widgets starting with "btn_"

`get_widget_info`

Get detailed widget information.

get_widget_info(widget_name="submit_button")
# Returns: type, visible, enabled, size, position, text, checked state, etc.

`get_app_status`

Check if the application is still running and get diagnostics.

get_app_status()
# Returns: {"running": true, "exit_code": null, "stderr": "", "display": ":99"}

`wait_for_idle`

Wait 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_app`

Close the running application.

close_app()

Requirements for Target Applications

For widget interactions to work, your Qt application must:

  1. Set object names on interactive widgets:

    button = QPushButton("Click Me")
    button.setObjectName("my_button")  # Required for widget discovery
    
  2. Use QApplication (not QCoreApplication)

  3. Show at least one window

Architecture

┌─────────────────────────────┐
│  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        │
└─────────────────────────────┘

Example Workflow

# 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()

Troubleshooting

"Widget not found"

  • Ensure the widget has setObjectName() called
  • Use find_widgets() to list available widget names

"No

Frequently Asked Questions

What are the key features of Qt Pilot?

Launch Qt applications headlessly via Xvfb. Capture screenshots for visual verification. Simulate user interactions like clicks, hovers, and keyboard input. Discover and introspect widgets by object name. Monitor application health and capture stderr.

What can I use Qt Pilot for?

Automated GUI testing for Qt/PySide6 desktop applications. Visual regression testing by capturing and comparing screenshots. Headless CI/CD pipelines for desktop software. AI-assisted debugging of UI interactions in complex Qt applications.

How do I install Qt Pilot?

Install Qt Pilot by running: git clone https://github.com/neatobandit0/qt-pilot.git ~/.claude/plugins/qt-pilot && pip install -r ~/.claude/plugins/qt-pilot/requirements.txt

What MCP clients work with Qt Pilot?

Qt Pilot works with any MCP-compatible client including Claude Desktop, Claude Code, Cursor, and other editors with MCP support.

Conare · memory for coding agents

Turn this server into reusable context

Keep Qt Pilot docs, env vars, and workflow notes in Conare so your agent carries them across sessions.

Set up free$npx conare@latest